Merge "Don't generate EGL fence in single buffer mode"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 8bba81b..0e77850 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -96,6 +96,7 @@
{ "sched", "CPU Scheduling", 0, {
{ REQ, "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
{ REQ, "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
+ { OPT, "/sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable" },
} },
{ "irq", "IRQ Events", 0, {
{ REQ, "/sys/kernel/debug/tracing/events/irq/enable" },
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
index cde9c37..3373192 100644
--- a/cmds/atrace/atrace.rc
+++ b/cmds/atrace/atrace.rc
@@ -12,6 +12,7 @@
chown root shell /sys/kernel/debug/tracing/options/print-tgid
chown root shell /sys/kernel/debug/tracing/events/sched/sched_switch/enable
chown root shell /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
+ chown root shell /sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable
chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
chown root shell /sys/kernel/debug/tracing/events/power/cpu_idle/enable
chown root shell /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
@@ -34,6 +35,7 @@
chmod 0664 /sys/kernel/debug/tracing/options/print-tgid
chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_switch/enable
chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
+ chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_blocked_reason/enable
chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_idle/enable
chmod 0664 /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index 6442701..4ab8d3d 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -15,6 +15,8 @@
LOCAL_MODULE := dumpstate
LOCAL_SHARED_LIBRARIES := libcutils liblog libselinux
+# ZipArchive support, the order matters here to get all symbols.
+LOCAL_STATIC_LIBRARIES := libziparchive libz libbase
LOCAL_HAL_STATIC_LIBRARIES := libdumpstate
LOCAL_CFLAGS += -Wall -Wno-unused-parameter -std=gnu99
LOCAL_INIT_RC := dumpstate.rc
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 7560416..4703c2f 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -18,9 +18,11 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
+#include <memory>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string>
#include <string.h>
#include <sys/capability.h>
#include <sys/prctl.h>
@@ -30,6 +32,7 @@
#include <sys/wait.h>
#include <unistd.h>
+#include <base/stringprintf.h>
#include <cutils/properties.h>
#include "private/android_filesystem_config.h"
@@ -38,12 +41,16 @@
#include <cutils/log.h>
#include "dumpstate.h"
+#include "ScopedFd.h"
+#include "ziparchive/zip_writer.h"
+
+using android::base::StringPrintf;
/* read before root is shed */
static char cmdline_buf[16384] = "(unknown)";
static const char *dump_traces_path = NULL;
-static char screenshot_path[PATH_MAX] = "";
+static std::string screenshot_path;
#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
@@ -299,7 +306,7 @@
run_command("UPTIME", 10, "uptime", NULL);
dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
dump_file("MEMORY INFO", "/proc/meminfo");
- run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL);
+ run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL);
run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
dump_file("VMALLOC INFO", "/proc/vmallocinfo");
@@ -323,10 +330,11 @@
for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
- if (screenshot_path[0]) {
+ if (!screenshot_path.empty()) {
ALOGI("taking screenshot\n");
- run_command(NULL, 10, "/system/bin/screencap", "-p", screenshot_path, NULL);
- ALOGI("wrote screenshot: %s\n", screenshot_path);
+ const char *args[] = { "/system/bin/screencap", "-p", screenshot_path.c_str(), NULL };
+ run_command_always(NULL, 10, args);
+ ALOGI("wrote screenshot: %s\n", screenshot_path.c_str());
}
// dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
@@ -587,12 +595,13 @@
fprintf(stderr, "usage: dumpstate [-b soundfile] [-e soundfile] [-o file [-d] [-p] [-z]] [-s] [-q]\n"
" -o: write to file (instead of stdout)\n"
" -d: append date to filename (requires -o)\n"
+ " -z: generates zipped file (requires -o)\n"
" -p: capture screenshot to filename.png (requires -o)\n"
" -s: write output to control socket (for init)\n"
" -b: play sound file instead of vibrate, at beginning of job\n"
" -e: play sound file instead of vibrate, at end of job\n"
" -q: disable vibrate\n"
- " -B: send broadcast when finished (requires -o and -p)\n"
+ " -B: send broadcast when finished (requires -o)\n"
);
}
@@ -606,9 +615,71 @@
fflush(vibrator);
}
+/* generates a zipfile on 'path' with an entry with the contents of 'tmp_path'
+ and removes the temporary file.
+ */
+static bool generate_zip_file(std::string tmp_path, std::string path,
+ std::string entry_name, time_t entry_time) {
+ std::unique_ptr<FILE, int(*)(FILE*)> file(fopen(path.c_str(), "wb"), fclose);
+ if (!file) {
+ ALOGE("fopen(%s, 'wb'): %s\n", path.c_str(), strerror(errno));
+ return false;
+ }
+
+ ZipWriter writer(file.get());
+ int32_t err = writer.StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, entry_time);
+ if (err) {
+ ALOGE("writer.StartEntryWithTime(%s): %s\n", entry_name.c_str(), ZipWriter::ErrorCodeString(err));
+ return false;
+ }
+
+ ScopedFd fd(TEMP_FAILURE_RETRY(open(tmp_path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
+ if (fd.get() == -1) {
+ ALOGE("open(%s): %s\n", tmp_path.c_str(), strerror(errno));
+ return false;
+ }
+
+ while (1) {
+ std::vector<uint8_t> buffer(65536);
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd.get(), buffer.data(), sizeof(buffer)));
+ if (bytes_read == 0) {
+ break;
+ } else if (bytes_read == -1) {
+ ALOGE("read(%s): %s\n", tmp_path.c_str(), strerror(errno));
+ return false;
+ }
+ err = writer.WriteBytes(buffer.data(), bytes_read);
+ if (err) {
+ ALOGE("writer.WriteBytes(): %s\n", ZipWriter::ErrorCodeString(err));
+ return false;
+ }
+ }
+
+ err = writer.FinishEntry();
+ if (err) {
+ ALOGE("writer.FinishEntry(): %s\n", ZipWriter::ErrorCodeString(err));
+ return false;
+ }
+
+ err = writer.Finish();
+ if (err) {
+ ALOGE("writer.Finish(): %s\n", ZipWriter::ErrorCodeString(err));
+ return false;
+ }
+
+ if (remove(tmp_path.c_str())) {
+ ALOGE("remove(%s): %s\n", tmp_path.c_str(), strerror(errno));
+ return false;
+ }
+
+ return true;
+}
+
+
int main(int argc, char *argv[]) {
struct sigaction sigact;
int do_add_date = 0;
+ int do_zip_file = 0;
int do_vibrate = 1;
char* use_outfile = 0;
int use_socket = 0;
@@ -644,6 +715,7 @@
while ((c = getopt(argc, argv, "dho:svqzpB")) != -1) {
switch (c) {
case 'd': do_add_date = 1; break;
+ case 'z': do_zip_file = 1; break;
case 'o': use_outfile = optarg; break;
case 's': use_socket = 1; break;
case 'v': break; // compatibility no-op
@@ -657,6 +729,12 @@
}
}
+ if ((do_zip_file || do_add_date || do_broadcast) && !use_outfile) {
+ usage();
+ exit(1);
+ }
+
+
// If we are going to use a socket, do it as early as possible
// to avoid timeouts from bugreport.
if (use_socket) {
@@ -664,17 +742,17 @@
}
/* open the vibrator before dropping root */
- FILE *vibrator = 0;
+ std::unique_ptr<FILE, int(*)(FILE*)> vibrator(NULL, fclose);
if (do_vibrate) {
- vibrator = fopen("/sys/class/timed_output/vibrator/enable", "we");
+ vibrator.reset(fopen("/sys/class/timed_output/vibrator/enable", "we"));
if (vibrator) {
- vibrate(vibrator, 150);
+ vibrate(vibrator.get(), 150);
}
}
/* read /proc/cmdline before dropping root */
FILE *cmdline = fopen("/proc/cmdline", "re");
- if (cmdline != NULL) {
+ if (cmdline) {
fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
fclose(cmdline);
}
@@ -725,25 +803,34 @@
}
/* redirect output if needed */
- char path[PATH_MAX], tmp_path[PATH_MAX];
- pid_t gzip_pid = -1;
+ std::string text_path, zip_path, tmp_path, entry_name;
+
+ /* pointer to the actual path, be it zip or text */
+ std::string path;
+
+ time_t now = time(NULL);
if (!use_socket && use_outfile) {
- strlcpy(path, use_outfile, sizeof(path));
+ text_path = use_outfile;
if (do_add_date) {
char date[80];
- time_t now = time(NULL);
strftime(date, sizeof(date), "-%Y-%m-%d-%H-%M-%S", localtime(&now));
- strlcat(path, date, sizeof(path));
+ text_path += date;
}
if (do_fb) {
- strlcpy(screenshot_path, path, sizeof(screenshot_path));
- strlcat(screenshot_path, ".png", sizeof(screenshot_path));
+ screenshot_path = text_path + ".png";
}
- strlcat(path, ".txt", sizeof(path));
- strlcpy(tmp_path, path, sizeof(tmp_path));
- strlcat(tmp_path, ".tmp", sizeof(tmp_path));
- redirect_to_file(stdout, tmp_path);
+ zip_path = text_path + ".zip";
+ text_path += ".txt";
+ tmp_path = text_path + ".tmp";
+ entry_name = basename(text_path.c_str());
+
+ ALOGD("Temporary path: %s\ntext path: %s\nzip path: %s\nzip entry: %s",
+ tmp_path.c_str(), text_path.c_str(), zip_path.c_str(), entry_name.c_str());
+ /* TODO: rather than generating a text file now and zipping it later,
+ it would be more efficient to redirect stdout to the zip entry
+ directly, but the libziparchive doesn't support that option yet. */
+ redirect_to_file(stdout, const_cast<char*>(tmp_path.c_str()));
}
dumpstate();
@@ -751,30 +838,54 @@
/* done */
if (vibrator) {
for (int i = 0; i < 3; i++) {
- vibrate(vibrator, 75);
+ vibrate(vibrator.get(), 75);
usleep((75 + 50) * 1000);
}
- fclose(vibrator);
}
- /* wait for gzip to finish, otherwise it might get killed when we exit */
- if (gzip_pid > 0) {
+ /* close output if needed */
+ if (!use_socket && use_outfile) {
fclose(stdout);
- waitpid(gzip_pid, NULL, 0);
}
- /* rename the (now complete) .tmp file to its final location */
- if (use_outfile && rename(tmp_path, path)) {
- fprintf(stderr, "rename(%s, %s): %s\n", tmp_path, path, strerror(errno));
+ /* rename or zip the (now complete) .tmp file to its final location */
+ if (use_outfile) {
+ bool do_text_file = true;
+ if (do_zip_file) {
+ path = zip_path;
+ if (!generate_zip_file(tmp_path, zip_path, entry_name, now)) {
+ ALOGE("Failed to generate zip file; sending text bugreport instead\n");
+ do_text_file = true;
+ } else {
+ do_text_file = false;
+ }
+ }
+ if (do_text_file) {
+ path = text_path;
+ if (rename(tmp_path.c_str(), text_path.c_str())) {
+ ALOGE("rename(%s, %s): %s\n", tmp_path.c_str(), text_path.c_str(), strerror(errno));
+ path.clear();
+ }
+ }
}
/* tell activity manager we're done */
- if (do_broadcast && use_outfile && do_fb) {
- run_command(NULL, 5, "/system/bin/am", "broadcast", "--user", "0",
- "-a", "android.intent.action.BUGREPORT_FINISHED",
- "--es", "android.intent.extra.BUGREPORT", path,
- "--es", "android.intent.extra.SCREENSHOT", screenshot_path,
- "--receiver-permission", "android.permission.DUMP", NULL);
+ if (do_broadcast && use_outfile) {
+ if (!path.empty()) {
+ ALOGI("Final bugreport path: %s\n", path.c_str());
+ std::vector<std::string> am_args = {
+ "--receiver-permission", "android.permission.DUMP",
+ "--es", "android.intent.extra.BUGREPORT", path
+ };
+ if (do_fb) {
+ am_args.push_back("--es");
+ am_args.push_back("android.intent.extra.SCREENSHOT");
+ am_args.push_back(screenshot_path);
+ }
+ send_broadcast("android.intent.action.BUGREPORT_FINISHED", am_args);
+ } else {
+ ALOGE("Skipping broadcast because bugreport could not be generated\n");
+ }
}
ALOGI("done\n");
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index f10ec46..18ee168 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -17,10 +17,24 @@
#ifndef _DUMPSTATE_H_
#define _DUMPSTATE_H_
+/* When defined, skips the real dumps and just print the section headers.
+ Useful when debugging dumpstate itself. */
+//#define _DUMPSTATE_DRY_RUN_
+
+#ifdef _DUMPSTATE_DRY_RUN_
+#define ON_DRY_RUN_RETURN(X) return X
+#define ON_DRY_RUN(code) code
+#else
+#define ON_DRY_RUN_RETURN(X)
+#define ON_DRY_RUN(code)
+#endif
+
+
#include <time.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdio.h>
+#include <vector>
#define SU_PATH "/system/xbin/su"
@@ -52,6 +66,14 @@
/* forks a command and waits for it to finish -- terminate args with NULL */
int run_command(const char *title, int timeout_seconds, const char *command, ...);
+/* forks a command and waits for it to finish
+ first element of args is the command, and last must be NULL.
+ command is always ran, even when _DUMPSTATE_DRY_RUN_ is defined. */
+int run_command_always(const char *title, int timeout_seconds, const char *args[]);
+
+/* sends a broadcast using Activity Manager */
+void send_broadcast(const std::string& action, const std::vector<std::string>& args);
+
/* prints all the system properties */
void print_properties();
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 12f44ae..4316c96 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -23,6 +23,7 @@
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string>
#include <string.h>
#include <sys/inotify.h>
#include <sys/stat.h>
@@ -31,6 +32,7 @@
#include <sys/klog.h>
#include <time.h>
#include <unistd.h>
+#include <vector>
#include <sys/prctl.h>
#include <cutils/debugger.h>
@@ -50,6 +52,7 @@
"/system/bin/mediaserver",
"/system/bin/sdcard",
"/system/bin/surfaceflinger",
+ "/system/bin/vehicle_network_service",
NULL,
};
@@ -60,6 +63,7 @@
}
void for_each_userid(void (*func)(int), const char *header) {
+ ON_DRY_RUN_RETURN();
DIR *d;
struct dirent *de;
@@ -122,6 +126,7 @@
}
void for_each_pid(for_each_pid_func func, const char *header) {
+ ON_DRY_RUN_RETURN();
__for_each_pid(for_each_pid_helper, header, (void *)func);
}
@@ -174,10 +179,12 @@
}
void for_each_tid(for_each_tid_func func, const char *header) {
+ ON_DRY_RUN_RETURN();
__for_each_pid(for_each_tid_helper, header, (void *) func);
}
void show_wchan(int pid, int tid, const char *name) {
+ ON_DRY_RUN_RETURN();
char path[255];
char buffer[255];
int fd;
@@ -208,6 +215,7 @@
void do_dmesg() {
printf("------ KERNEL LOG (dmesg) ------\n");
+ ON_DRY_RUN_RETURN();
/* Get size of kernel buffer */
int size = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
if (size <= 0) {
@@ -241,11 +249,16 @@
}
static int _dump_file_from_fd(const char *title, const char *path, int fd) {
- if (title) printf("------ %s (%s", title, path);
-
if (title) {
+ printf("------ %s (%s", title, path);
+
struct stat st;
- if (memcmp(path, "/proc/", 6) && memcmp(path, "/sys/", 5) && !fstat(fd, &st)) {
+ // Only show the modification time of non-device files.
+ size_t path_len = strlen(path);
+ if ((path_len < 6 || memcmp(path, "/proc/", 6)) &&
+ (path_len < 5 || memcmp(path, "/sys/", 5)) &&
+ (path_len < 3 || memcmp(path, "/d/", 3)) &&
+ !fstat(fd, &st)) {
char stamp[80];
time_t mtime = st.st_mtime;
strftime(stamp, sizeof(stamp), "%Y-%m-%d %H:%M:%S", localtime(&mtime));
@@ -253,6 +266,7 @@
}
printf(") ------\n");
}
+ ON_DRY_RUN({ close(fd); return 0; });
bool newline = false;
fd_set read_set;
@@ -302,7 +316,6 @@
int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
if (fd < 0) {
int err = errno;
- if (title) printf("------ %s (%s) ------\n", title, path);
printf("*** %s: %s\n", path, strerror(err));
if (title) printf("\n");
return -1;
@@ -328,6 +341,7 @@
if (title) {
printf("------ %s (%s) ------\n", title, dir);
}
+ ON_DRY_RUN_RETURN(0);
if (dir[strlen(dir) - 1] == '/') {
++slash;
@@ -387,9 +401,11 @@
int flags = fcntl(fd, F_GETFL);
if (flags == -1) {
printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
+ close(fd);
return -1;
} else if (!(flags & O_NONBLOCK)) {
printf("*** %s: fd must have O_NONBLOCK set.\n", path);
+ close(fd);
return -1;
}
return _dump_file_from_fd(title, path, fd);
@@ -442,6 +458,29 @@
/* forks a command and waits for it to finish */
int run_command(const char *title, int timeout_seconds, const char *command, ...) {
fflush(stdout);
+
+ const char *args[1024] = {command};
+ size_t arg;
+ va_list ap;
+ va_start(ap, command);
+ if (title) printf("------ %s (%s", title, command);
+ for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
+ args[arg] = va_arg(ap, const char *);
+ if (args[arg] == NULL) break;
+ if (title) printf(" %s", args[arg]);
+ }
+ if (title) printf(") ------\n");
+ fflush(stdout);
+
+ ON_DRY_RUN_RETURN(0);
+
+ return run_command_always(title, timeout_seconds, args);
+}
+
+/* forks a command and waits for it to finish */
+int run_command_always(const char *title, int timeout_seconds, const char *args[]) {
+
+ const char *command = args[0];
uint64_t start = nanotime();
pid_t pid = fork();
@@ -453,8 +492,6 @@
/* handle child case */
if (pid == 0) {
- const char *args[1024] = {command};
- size_t arg;
/* make sure the child dies when dumpstate dies */
prctl(PR_SET_PDEATHSIG, SIGKILL);
@@ -465,17 +502,6 @@
sigact.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sigact, NULL);
- va_list ap;
- va_start(ap, command);
- if (title) printf("------ %s (%s", title, command);
- for (arg = 1; arg < sizeof(args) / sizeof(args[0]); ++arg) {
- args[arg] = va_arg(ap, const char *);
- if (args[arg] == NULL) break;
- if (title) printf(" %s", args[arg]);
- }
- if (title) printf(") ------\n");
- fflush(stdout);
-
execvp(command, (char**) args);
printf("*** exec(%s): %s\n", command, strerror(errno));
fflush(stdout);
@@ -514,6 +540,22 @@
return status;
}
+void send_broadcast(const std::string& action, const std::vector<std::string>& args) {
+ if (args.size() > 1000) {
+ fprintf(stderr, "send_broadcast: too many arguments (%d)\n", args.size());
+ return;
+ }
+ const char *am_args[1024] = { "/system/bin/am", "broadcast", "--user", "0",
+ "-a", action.c_str() };
+ size_t am_index = 5; // Starts at the index of last initial value above.
+ for (const std::string& arg : args) {
+ am_args[++am_index] = arg.c_str();
+ }
+ // Always terminate with NULL.
+ am_args[am_index + 1] = NULL;
+ run_command_always(NULL, 5, am_args);
+}
+
size_t num_props = 0;
static char* props[2000];
@@ -532,12 +574,13 @@
/* prints all the system properties */
void print_properties() {
+ printf("------ SYSTEM PROPERTIES ------\n");
+ ON_DRY_RUN_RETURN();
size_t i;
num_props = 0;
property_list(print_prop, NULL);
qsort(&props, num_props, sizeof(props[0]), compare_prop);
- printf("------ SYSTEM PROPERTIES ------\n");
for (i = 0; i < num_props; ++i) {
fputs(props[i], stdout);
free(props[i]);
@@ -611,6 +654,7 @@
/* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
const char *dump_traces() {
+ ON_DRY_RUN_RETURN(NULL);
const char* result = NULL;
char traces_path[PROPERTY_VALUE_MAX] = "";
@@ -764,6 +808,7 @@
}
void dump_route_tables() {
+ ON_DRY_RUN_RETURN();
const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
dump_file("RT_TABLES", RT_TABLES_PATH);
FILE* fp = fopen(RT_TABLES_PATH, "re");
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index 46d72fd..2fd5cd2 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -43,67 +43,24 @@
static const char* kCpPath = "/system/bin/cp";
-int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const char *seinfo)
-{
+int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const char *seinfo) {
if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
ALOGE("invalid uid/gid: %d %d\n", uid, gid);
return -1;
}
- std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname));
- const char* pkgdir = _pkgdir.c_str();
-
- if (mkdir(pkgdir, 0751) < 0) {
- ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
- return -1;
- }
- if (chmod(pkgdir, 0751) < 0) {
- ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
- unlink(pkgdir);
- return -1;
- }
-
- if (selinux_android_setfilecon(pkgdir, pkgname, seinfo, uid) < 0) {
- ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
- unlink(pkgdir);
- return -errno;
- }
-
- if (chown(pkgdir, uid, gid) < 0) {
- ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
- unlink(pkgdir);
- return -1;
- }
-
- return 0;
+ return make_user_data(uuid, pkgname, uid, 0, seinfo);
}
-int uninstall(const char *uuid, const char *pkgname, userid_t userid)
-{
- std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname));
- const char* pkgdir = _pkgdir.c_str();
+int uninstall(const char *uuid, const char *pkgname, userid_t userid) {
+ std::string ce_package_path(create_data_user_package_path(uuid, userid, pkgname));
+ std::string de_package_path(create_data_user_de_package_path(uuid, userid, pkgname));
- remove_profile_file(pkgname);
-
- /* delete contents AND directory, no exceptions */
- return delete_dir_contents(pkgdir, 1, NULL);
-}
-
-int renamepkg(const char *oldpkgname, const char *newpkgname)
-{
- char oldpkgdir[PKG_PATH_MAX];
- char newpkgdir[PKG_PATH_MAX];
-
- if (create_pkg_path(oldpkgdir, oldpkgname, PKG_DIR_POSTFIX, 0))
- return -1;
- if (create_pkg_path(newpkgdir, newpkgname, PKG_DIR_POSTFIX, 0))
- return -1;
-
- if (rename(oldpkgdir, newpkgdir) < 0) {
- ALOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno));
- return -errno;
- }
- return 0;
+ int res = 0;
+ res |= delete_dir_contents_and_dir(ce_package_path);
+ // TODO: include result once 25796509 is fixed
+ delete_dir_contents_and_dir(de_package_path);
+ return res;
}
int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid)
@@ -115,6 +72,7 @@
return -1;
}
+ // TODO: handle user_de paths
std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname));
const char* pkgdir = _pkgdir.c_str();
@@ -139,39 +97,47 @@
return 0;
}
-int delete_user_data(const char *uuid, const char *pkgname, userid_t userid)
-{
- std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname));
- const char* pkgdir = _pkgdir.c_str();
+int delete_user_data(const char *uuid, const char *pkgname, userid_t userid) {
+ std::string ce_package_path(create_data_user_package_path(uuid, userid, pkgname));
+ std::string de_package_path(create_data_user_de_package_path(uuid, userid, pkgname));
- return delete_dir_contents(pkgdir, 0, NULL);
+ int res = 0;
+ res |= delete_dir_contents(ce_package_path);
+ // TODO: include result once 25796509 is fixed
+ delete_dir_contents(de_package_path);
+ return res;
}
-int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t userid, const char* seinfo)
-{
- std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname));
- const char* pkgdir = _pkgdir.c_str();
+int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t userid,
+ const char* seinfo) {
+ std::string ce_package_path(create_data_user_package_path(uuid, userid, pkgname));
+ std::string de_package_path(create_data_user_de_package_path(uuid, userid, pkgname));
- if (mkdir(pkgdir, 0751) < 0) {
- ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
- return -errno;
+ const char* c_ce_package_path = ce_package_path.c_str();
+ const char* c_de_package_path = de_package_path.c_str();
+
+ if (fs_prepare_dir(c_ce_package_path, 0751, uid, uid) == -1) {
+ PLOG(ERROR) << "Failed to prepare " << ce_package_path;
+ unlink(c_ce_package_path);
+ return -1;
}
- if (chmod(pkgdir, 0751) < 0) {
- ALOGE("cannot chmod dir '%s': %s\n", pkgdir, strerror(errno));
- unlink(pkgdir);
- return -errno;
+ if (selinux_android_setfilecon(c_ce_package_path, pkgname, seinfo, uid) < 0) {
+ PLOG(ERROR) << "Failed to setfilecon " << ce_package_path;
+ unlink(c_ce_package_path);
+ return -1;
}
- if (selinux_android_setfilecon(pkgdir, pkgname, seinfo, uid) < 0) {
- ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
- unlink(pkgdir);
- return -errno;
+ if (fs_prepare_dir(c_de_package_path, 0751, uid, uid) == -1) {
+ PLOG(ERROR) << "Failed to prepare " << de_package_path;
+ unlink(c_de_package_path);
+ // TODO: include result once 25796509 is fixed
+ return 0;
}
-
- if (chown(pkgdir, uid, uid) < 0) {
- ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
- unlink(pkgdir);
- return -errno;
+ if (selinux_android_setfilecon(c_de_package_path, pkgname, seinfo, uid) < 0) {
+ PLOG(ERROR) << "Failed to setfilecon " << de_package_path;
+ unlink(c_de_package_path);
+ // TODO: include result once 25796509 is fixed
+ return 0;
}
return 0;
@@ -215,6 +181,7 @@
}
// Copy private data for all known users
+ // TODO: handle user_de paths
for (auto user : users) {
std::string from(create_data_user_package_path(from_uuid, user, package_name));
std::string to(create_data_user_package_path(to_uuid, user, package_name));
@@ -295,30 +262,27 @@
return 0;
}
-int delete_user(const char *uuid, userid_t userid)
-{
- int status = 0;
+int delete_user(const char *uuid, userid_t userid) {
+ int res = 0;
std::string data_path(create_data_user_path(uuid, userid));
- if (delete_dir_contents(data_path.c_str(), 1, NULL) != 0) {
- status = -1;
- }
-
+ std::string data_de_path(create_data_user_de_path(uuid, userid));
std::string media_path(create_data_media_path(uuid, userid));
- if (delete_dir_contents(media_path.c_str(), 1, NULL) != 0) {
- status = -1;
- }
+
+ res |= delete_dir_contents_and_dir(data_path);
+ res |= delete_dir_contents_and_dir(data_de_path);
+ res |= delete_dir_contents_and_dir(media_path);
// Config paths only exist on internal storage
if (uuid == nullptr) {
char config_path[PATH_MAX];
if ((create_user_config_path(config_path, userid) != 0)
|| (delete_dir_contents(config_path, 1, NULL) != 0)) {
- status = -1;
+ res = -1;
}
}
- return status;
+ return res;
}
int delete_cache(const char *uuid, const char *pkgname, userid_t userid)
@@ -561,6 +525,7 @@
}
for (auto user : users) {
+ // TODO: handle user_de directories
std::string _pkgdir(create_data_user_package_path(uuid, user, pkgname));
const char* pkgdir = _pkgdir.c_str();
@@ -745,7 +710,7 @@
}
static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
- const char* output_file_name, int swap_fd, const char *pkgname, const char *instruction_set,
+ const char* output_file_name, int swap_fd, const char *instruction_set,
bool vm_safe_mode, bool debuggable, bool post_bootcomplete, bool use_jit)
{
static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
@@ -756,9 +721,6 @@
return;
}
- char prop_buf[PROPERTY_VALUE_MAX];
- bool profiler = (property_get("dalvik.vm.profiler", prop_buf, "0") > 0) && (prop_buf[0] == '1');
-
char dex2oat_Xms_flag[PROPERTY_VALUE_MAX];
bool have_dex2oat_Xms_flag = property_get("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, NULL) > 0;
@@ -822,8 +784,6 @@
char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
char instruction_set_variant_arg[strlen("--instruction-set-variant=") + PROPERTY_VALUE_MAX];
char instruction_set_features_arg[strlen("--instruction-set-features=") + PROPERTY_VALUE_MAX];
- char profile_file_arg[strlen("--profile-file=") + PKG_PATH_MAX];
- char top_k_profile_threshold_arg[strlen("--top-k-profile-threshold=") + PROPERTY_VALUE_MAX];
char dex2oat_Xms_arg[strlen("-Xms") + PROPERTY_VALUE_MAX];
char dex2oat_Xmx_arg[strlen("-Xmx") + PROPERTY_VALUE_MAX];
char dex2oat_compiler_filter_arg[strlen("--compiler-filter=") + PROPERTY_VALUE_MAX];
@@ -842,24 +802,6 @@
sprintf(dex2oat_swap_fd, "--swap-fd=%d", swap_fd);
}
- bool have_profile_file = false;
- bool have_top_k_profile_threshold = false;
- if (profiler && (strcmp(pkgname, "*") != 0)) {
- char profile_file[PKG_PATH_MAX];
- snprintf(profile_file, sizeof(profile_file), "%s/%s",
- DALVIK_CACHE_PREFIX "profiles", pkgname);
- struct stat st;
- if ((stat(profile_file, &st) == 0) && (st.st_size > 0)) {
- sprintf(profile_file_arg, "--profile-file=%s", profile_file);
- have_profile_file = true;
- if (property_get("dalvik.vm.profile.top-k-thr", prop_buf, NULL) > 0) {
- snprintf(top_k_profile_threshold_arg, sizeof(top_k_profile_threshold_arg),
- "--top-k-profile-threshold=%s", prop_buf);
- have_top_k_profile_threshold = true;
- }
- }
- }
-
// use the JIT if either it's specified as a dexopt flag or if the property is set
use_jit = use_jit || check_boolean_property("debug.usejit");
if (have_dex2oat_Xms_flag) {
@@ -884,6 +826,7 @@
// Check whether all apps should be compiled debuggable.
if (!debuggable) {
+ char prop_buf[PROPERTY_VALUE_MAX];
debuggable =
(property_get("dalvik.vm.always_debuggable", prop_buf, "0") > 0) &&
(prop_buf[0] == '1');
@@ -894,8 +837,6 @@
const char* argv[7 // program name, mandatory arguments and the final NULL
+ (have_dex2oat_isa_variant ? 1 : 0)
+ (have_dex2oat_isa_features ? 1 : 0)
- + (have_profile_file ? 1 : 0)
- + (have_top_k_profile_threshold ? 1 : 0)
+ (have_dex2oat_Xms_flag ? 2 : 0)
+ (have_dex2oat_Xmx_flag ? 2 : 0)
+ (have_dex2oat_compiler_filter_flag ? 1 : 0)
@@ -918,12 +859,6 @@
if (have_dex2oat_isa_features) {
argv[i++] = instruction_set_features_arg;
}
- if (have_profile_file) {
- argv[i++] = profile_file_arg;
- }
- if (have_top_k_profile_threshold) {
- argv[i++] = top_k_profile_threshold_arg;
- }
if (have_dex2oat_Xms_flag) {
argv[i++] = RUNTIME_ARG;
argv[i++] = dex2oat_Xms_arg;
@@ -1098,7 +1033,7 @@
bool boot_complete = (dexopt_flags & DEXOPT_BOOTCOMPLETE) != 0;
bool use_jit = (dexopt_flags & DEXOPT_USEJIT) != 0;
- if ((dexopt_flags & DEXOPT_MASK) != 0) {
+ if ((dexopt_flags & ~DEXOPT_MASK) != 0) {
LOG_FATAL("dexopt flags contains unknown fields\n");
}
@@ -1171,11 +1106,6 @@
goto fail;
}
- // Create profile file if there is a package name present.
- if (strcmp(pkgname, "*") != 0) {
- create_profile_file(pkgname, uid);
- }
-
// Create a swap file if necessary.
if (ShouldUseSwapFileForDexopt()) {
// Make sure there really is enough space.
@@ -1239,7 +1169,7 @@
} else {
input_file_name++;
}
- run_dex2oat(input_fd, out_fd, input_file_name, out_path, swap_fd, pkgname,
+ run_dex2oat(input_fd, out_fd, input_file_name, out_path, swap_fd,
instruction_set, vm_safe_mode, debuggable, boot_complete, use_jit);
} else {
ALOGE("Invalid dexopt needed: %d\n", dexopt_needed);
@@ -1731,13 +1661,8 @@
return -1;
}
-int restorecon_data(const char* uuid, const char* pkgName,
- const char* seinfo, uid_t uid)
-{
- struct dirent *entry;
- DIR *d;
- struct stat s;
- int ret = 0;
+int restorecon_data(const char* uuid, const char* pkgName, const char* seinfo, appid_t appid) {
+ int res = 0;
// SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here.
unsigned int flags = SELINUX_ANDROID_RESTORECON_RECURSE;
@@ -1747,53 +1672,25 @@
return -1;
}
- // Special case for owner on internal storage
- if (uuid == nullptr) {
- std::string path(create_data_user_package_path(nullptr, 0, pkgName));
+ // Relabel package directory for all users
+ std::vector<userid_t> users = get_known_users(uuid);
+ for (auto user : users) {
+ uid_t uid = multiuser_get_uid(user, appid);
- if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, flags) < 0) {
- PLOG(ERROR) << "restorecon failed for " << path;
- ret |= -1;
+ std::string ce_package_path(create_data_user_package_path(uuid, user, pkgName));
+ std::string de_package_path(create_data_user_de_package_path(uuid, user, pkgName));
+
+ if (selinux_android_restorecon_pkgdir(ce_package_path.c_str(), seinfo, uid, flags) < 0) {
+ PLOG(ERROR) << "restorecon failed for " << ce_package_path;
+ res = -1;
+ }
+ if (selinux_android_restorecon_pkgdir(de_package_path.c_str(), seinfo, uid, flags) < 0) {
+ PLOG(ERROR) << "restorecon failed for " << de_package_path;
+ // TODO: include result once 25796509 is fixed
}
}
- // Relabel package directory for all secondary users.
- std::string userdir(create_data_path(uuid) + "/" + SECONDARY_USER_PREFIX);
- d = opendir(userdir.c_str());
- if (d == NULL) {
- return -1;
- }
-
- while ((entry = readdir(d))) {
- if (entry->d_type != DT_DIR) {
- continue;
- }
-
- const char *user = entry->d_name;
- // Ignore "." and ".."
- if (!strcmp(user, ".") || !strcmp(user, "..")) {
- continue;
- }
-
- // user directories start with a number
- if (user[0] < '0' || user[0] > '9') {
- ALOGE("Expecting numbered directory during restorecon. Instead got '%s'.", user);
- continue;
- }
-
- std::string pkgdir(StringPrintf("%s%s/%s", userdir.c_str(), user, pkgName));
- if (stat(pkgdir.c_str(), &s) < 0) {
- continue;
- }
-
- if (selinux_android_restorecon_pkgdir(pkgdir.c_str(), seinfo, s.st_uid, flags) < 0) {
- PLOG(ERROR) << "restorecon failed for " << pkgdir;
- ret |= -1;
- }
- }
-
- closedir(d);
- return ret;
+ return res;
}
int create_oat_dir(const char* oat_dir, const char* instruction_set)
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 7a16150..52f7b9c 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -72,11 +72,6 @@
return uninstall(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */
}
-static int do_rename(char **arg, char reply[REPLY_MAX] __unused)
-{
- return renamepkg(arg[0], arg[1]); /* oldpkgname, newpkgname */
-}
-
static int do_fixuid(char **arg, char reply[REPLY_MAX] __unused)
{
return fix_uid(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3])); /* uuid, pkgname, uid, gid */
@@ -198,7 +193,6 @@
{ "movedex", 3, do_move_dex },
{ "rmdex", 2, do_rm_dex },
{ "remove", 3, do_remove },
- { "rename", 2, do_rename },
{ "fixuid", 4, do_fixuid },
{ "freecache", 2, do_free_cache },
{ "rmcache", 3, do_rm_cache },
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index df13fe4..d911c49 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -2,16 +2,16 @@
**
** Copyright 2008, The Android Open Source Project
**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You may obtain a copy of the License at
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
**
-** http://www.apache.org/licenses/LICENSE-2.0
+** http://www.apache.org/licenses/LICENSE-2.0
**
-** Unless required by applicable law or agreed to in writing, software
-** distributed under the License is distributed on an "AS IS" BASIS,
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-** See the License for the specific language governing permissions and
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
** limitations under the License.
*/
@@ -171,10 +171,14 @@
std::string create_data_app_package_path(const char* volume_uuid, const char* package_name);
+// TODO: finish refactoring to "_ce"
std::string create_data_user_path(const char* volume_uuid, userid_t userid);
+std::string create_data_user_de_path(const char* volume_uuid, userid_t userid);
std::string create_data_user_package_path(const char* volume_uuid,
userid_t user, const char* package_name);
+std::string create_data_user_de_package_path(const char* volume_uuid,
+ userid_t user, const char* package_name);
std::string create_data_media_path(const char* volume_uuid, userid_t userid);
@@ -192,6 +196,9 @@
int create_cache_path(char path[PKG_PATH_MAX], const char *src,
const char *instruction_set);
+int delete_dir_contents(const std::string& pathname);
+int delete_dir_contents_and_dir(const std::string& pathname);
+
int delete_dir_contents(const char *pathname,
int also_delete_dir,
int (*exclusion_predicate)(const char *name, const int is_dir));
@@ -231,8 +238,6 @@
int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
int ensure_media_user_dirs(const char* uuid, userid_t userid);
int ensure_config_user_dirs(userid_t userid);
-int create_profile_file(const char *pkgname, gid_t gid);
-void remove_profile_file(const char *pkgname);
/* commands.c */
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index e58391f..549a420 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -64,6 +64,15 @@
create_data_user_path(volume_uuid, user).c_str(), package_name);
}
+std::string create_data_user_de_package_path(const char* volume_uuid,
+ userid_t user, const char* package_name) {
+ CHECK(is_valid_filename(package_name));
+ CHECK(is_valid_package_name(package_name) == 0);
+
+ return StringPrintf("%s/%s",
+ create_data_user_de_path(volume_uuid, user).c_str(), package_name);
+}
+
int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
const char *postfix, userid_t userid) {
if (is_valid_package_name(pkgname) != 0) {
@@ -115,6 +124,14 @@
}
/**
+ * Create the path name for device encrypted user data for a certain userid.
+ */
+std::string create_data_user_de_path(const char* volume_uuid, userid_t userid) {
+ std::string data(create_data_path(volume_uuid));
+ return StringPrintf("%s/user_de/%u", data.c_str(), userid);
+}
+
+/**
* Create the path name for media for a certain userid.
*/
std::string create_data_media_path(const char* volume_uuid, userid_t userid) {
@@ -288,6 +305,14 @@
return result;
}
+int delete_dir_contents(const std::string& pathname) {
+ return delete_dir_contents(pathname.c_str(), 0, NULL);
+}
+
+int delete_dir_contents_and_dir(const std::string& pathname) {
+ return delete_dir_contents(pathname.c_str(), 1, NULL);
+}
+
int delete_dir_contents(const char *pathname,
int also_delete_dir,
int (*exclusion_predicate)(const char*, const int))
@@ -1143,42 +1168,3 @@
return 0;
}
-
-int create_profile_file(const char *pkgname, gid_t gid) {
- const char *profile_dir = DALVIK_CACHE_PREFIX "profiles";
- char profile_file[PKG_PATH_MAX];
-
- snprintf(profile_file, sizeof(profile_file), "%s/%s", profile_dir, pkgname);
-
- // The 'system' user needs to be able to read the profile to determine if dex2oat
- // needs to be run. This is done in dalvik.system.DexFile.isDexOptNeededInternal(). So
- // we assign ownership to AID_SYSTEM and ensure it's not world-readable.
-
- int fd = open(profile_file, O_WRONLY | O_CREAT | O_NOFOLLOW | O_CLOEXEC, 0660);
-
- // Always set the uid/gid/permissions. The file could have been previously created
- // with different permissions.
- if (fd >= 0) {
- if (fchown(fd, AID_SYSTEM, gid) < 0) {
- ALOGE("cannot chown profile file '%s': %s\n", profile_file, strerror(errno));
- close(fd);
- unlink(profile_file);
- return -1;
- }
-
- if (fchmod(fd, 0660) < 0) {
- ALOGE("cannot chmod profile file '%s': %s\n", profile_file, strerror(errno));
- close(fd);
- unlink(profile_file);
- return -1;
- }
- close(fd);
- }
- return 0;
-}
-
-void remove_profile_file(const char *pkgname) {
- char profile_file[PKG_PATH_MAX];
- snprintf(profile_file, sizeof(profile_file), "%s/%s", DALVIK_CACHE_PREFIX "profiles", pkgname);
- unlink(profile_file);
-}
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 430c3ff..b6106ba 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -28,6 +28,7 @@
#include <linux/binder.h>
#include <binder/IInterface.h>
+#include <binder/Parcelable.h>
// ---------------------------------------------------------------------------
namespace android {
@@ -128,6 +129,10 @@
status_t writeStrongBinderVector(const std::vector<sp<IBinder>>& val);
template<typename T>
+ status_t writeParcelableVector(const std::vector<T>& val);
+ status_t writeParcelable(const Parcelable& parcelable);
+
+ template<typename T>
status_t write(const Flattenable<T>& val);
template<typename T>
@@ -204,6 +209,10 @@
wp<IBinder> readWeakBinder() const;
template<typename T>
+ status_t readParcelableVector(std::vector<T>* val) const;
+ status_t readParcelable(Parcelable* parcelable) const;
+
+ template<typename T>
status_t readStrongBinder(sp<T>* val) const;
status_t readStrongBinderVector(std::vector<sp<IBinder>>* val) const;
@@ -296,6 +305,22 @@
template<class T>
status_t writeAligned(T val);
+ template<typename T, typename U>
+ status_t unsafeReadTypedVector(std::vector<T>* val,
+ status_t(Parcel::*read_func)(U*) const) const;
+ template<typename T>
+ status_t readTypedVector(std::vector<T>* val,
+ status_t(Parcel::*read_func)(T*) const) const;
+ template<typename T, typename U>
+ status_t unsafeWriteTypedVector(const std::vector<T>& val,
+ status_t(Parcel::*write_func)(U));
+ template<typename T>
+ status_t writeTypedVector(const std::vector<T>& val,
+ status_t(Parcel::*write_func)(const T&));
+ template<typename T>
+ status_t writeTypedVector(const std::vector<T>& val,
+ status_t(Parcel::*write_func)(T));
+
status_t mError;
uint8_t* mData;
size_t mDataSize;
@@ -458,6 +483,87 @@
return ret;
}
+template<typename T, typename U>
+status_t Parcel::unsafeReadTypedVector(
+ std::vector<T>* val, status_t(Parcel::*read_func)(U*) const) const {
+ val->clear();
+
+ int32_t size;
+ status_t status = this->readInt32(&size);
+
+ if (status != OK) {
+ return status;
+ }
+
+ if (size < 0) {
+ return UNEXPECTED_NULL;
+ }
+
+ val->resize(size);
+
+ for (auto& v: *val) {
+ status = (this->*read_func)(&v);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+template<typename T>
+status_t Parcel::readTypedVector(std::vector<T>* val,
+ status_t(Parcel::*read_func)(T*) const) const {
+ return unsafeReadTypedVector(val, read_func);
+}
+
+template<typename T, typename U>
+status_t Parcel::unsafeWriteTypedVector(const std::vector<T>& val,
+ status_t(Parcel::*write_func)(U)) {
+ if (val.size() > std::numeric_limits<int32_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ status_t status = this->writeInt32(val.size());
+
+ if (status != OK) {
+ return status;
+ }
+
+ for (const auto& item : val) {
+ status = (this->*write_func)(item);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+template<typename T>
+status_t Parcel::writeTypedVector(const std::vector<T>& val,
+ status_t(Parcel::*write_func)(const T&)) {
+ return unsafeWriteTypedVector(val, write_func);
+}
+
+template<typename T>
+status_t Parcel::writeTypedVector(const std::vector<T>& val,
+ status_t(Parcel::*write_func)(T)) {
+ return unsafeWriteTypedVector(val, write_func);
+}
+
+template<typename T>
+status_t Parcel::readParcelableVector(std::vector<T>* val) const {
+ return unsafeReadTypedVector(val, &Parcel::readParcelable);
+}
+
+template<typename T>
+status_t Parcel::writeParcelableVector(const std::vector<T>& val) {
+ return unsafeWriteTypedVector(val, &Parcel::writeParcelable);
+}
+
// ---------------------------------------------------------------------------
inline TextOutput& operator<<(TextOutput& to, const Parcel& parcel)
diff --git a/include/binder/Parcelable.h b/include/binder/Parcelable.h
new file mode 100644
index 0000000..faf0d34
--- /dev/null
+++ b/include/binder/Parcelable.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_PARCELABLE_H
+#define ANDROID_PARCELABLE_H
+
+#include <vector>
+
+#include <utils/Errors.h>
+#include <utils/String16.h>
+
+namespace android {
+
+class Parcel;
+
+// Abstract interface of all parcelables.
+class Parcelable {
+public:
+ virtual ~Parcelable() = default;
+
+ // Write |this| parcelable to the given |parcel|. Keep in mind that
+ // implementations of writeToParcel must be manually kept in sync
+ // with readFromParcel and the Java equivalent versions of these methods.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ virtual status_t writeToParcel(Parcel* parcel) const = 0;
+
+ // Read data from the given |parcel| into |this|. After readFromParcel
+ // completes, |this| should have equivalent state to the object that
+ // wrote itself to the parcel.
+ //
+ // Returns android::OK on success and an appropriate error otherwise.
+ virtual status_t readFromParcel(const Parcel* parcel) = 0;
+}; // class Parcelable
+
+} // namespace android
+
+#endif // ANDROID_PARCELABLE_H
diff --git a/include/binder/Status.h b/include/binder/Status.h
new file mode 100644
index 0000000..04738f8
--- /dev/null
+++ b/include/binder/Status.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_BINDER_STATUS_H
+#define ANDROID_BINDER_STATUS_H
+
+#include <cstdint>
+
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace binder {
+
+// An object similar in function to a status_t except that it understands
+// how exceptions are encoded in the prefix of a Parcel. Used like:
+//
+// Parcel data;
+// Parcel reply;
+// status_t status;
+// binder::Status remote_exception;
+// if ((status = data.writeInterfaceToken(interface_descriptor)) != OK ||
+// (status = data.writeInt32(function_input)) != OK) {
+// // We failed to write into the memory of our local parcel?
+// }
+// if ((status = remote()->transact(transaction, data, &reply)) != OK) {
+// // Something has gone wrong in the binder driver or libbinder.
+// }
+// if ((status = remote_exception.readFromParcel(reply)) != OK) {
+// // The remote didn't correctly write the exception header to the
+// // reply.
+// }
+// if (!remote_exception.isOk()) {
+// // The transaction went through correctly, but the remote reported an
+// // exception during handling.
+// }
+//
+class Status final {
+public:
+ // Keep the exception codes in sync with android/os/Parcel.java.
+ enum Exception {
+ EX_NONE = 0,
+ EX_SECURITY = -1,
+ EX_BAD_PARCELABLE = -2,
+ EX_ILLEGAL_ARGUMENT = -3,
+ EX_NULL_POINTER = -4,
+ EX_ILLEGAL_STATE = -5,
+ EX_NETWORK_MAIN_THREAD = -6,
+ EX_UNSUPPORTED_OPERATION = -7,
+ EX_TRANSACTION_FAILED = -8,
+
+ // This is special and Java specific; see Parcel.java.
+ EX_HAS_REPLY_HEADER = -128,
+ };
+
+ // Allow authors to explicitly pick whether their integer is a status_t or
+ // exception code.
+ static Status fromExceptionCode(int32_t exception_code);
+ static Status fromStatusT(status_t status);
+ // A more readable alias for the default constructor.
+ static Status ok();
+
+ Status() = default;
+ Status(int32_t exception_code, const String8& message);
+ Status(int32_t exception_code, const char* message);
+
+
+ // Status objects are copyable and contain just simple data.
+ Status(const Status& status) = default;
+ Status(Status&& status) = default;
+ Status& operator=(const Status& status) = default;
+
+ ~Status() = default;
+
+ // Bear in mind that if the client or service is a Java endpoint, this
+ // is not the logic which will provide/interpret the data here.
+ status_t readFromParcel(const Parcel& parcel);
+ status_t writeToParcel(Parcel* parcel) const;
+
+ // Set one of the pre-defined exception types defined above.
+ void setException(int32_t ex, const String8& message);
+ // A few of the status_t values map to exception codes, but most of them
+ // simply map to "transaction failed."
+ void setFromStatusT(status_t status);
+
+ // Get information about an exception.
+ // Any argument may be given as nullptr.
+ void getException(int32_t* returned_exception,
+ String8* returned_message) const;
+ int32_t exceptionCode() const { return mException; }
+ const String8& exceptionMessage() const { return mMessage; }
+
+ bool isOk() const { return mException == EX_NONE; }
+
+ // For logging.
+ String8 toString8() const;
+
+private:
+ // We always write |mException| to the parcel.
+ // If |mException| != EX_NONE, we write message as well.
+ int32_t mException = EX_NONE;
+ String8 mMessage;
+}; // class Status
+
+} // namespace binder
+} // namespace android
+
+#endif // ANDROID_BINDER_STATUS_H
diff --git a/include/media/openmax/OMX_Core.h b/include/media/openmax/OMX_Core.h
index 521c223..f746a69 100644
--- a/include/media/openmax/OMX_Core.h
+++ b/include/media/openmax/OMX_Core.h
@@ -509,7 +509,7 @@
OMX_EventKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */
OMX_EventVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */
- /** Event when tunneled decoder has rendered an output
+ /** Event when tunneled decoder has rendered an output or reached EOS
* nData1 must contain the number of timestamps returned
* pEventData must point to an array of the OMX_VIDEO_RENDEREVENTTYPE structs containing the
* render-timestamps of each frame. Component may batch rendered timestamps using this event,
@@ -518,6 +518,10 @@
*
* If component is doing frame-rate conversion, it must signal the render time of each
* converted frame, and must interpolate media timestamps for in-between frames.
+ *
+ * When the component reached EOS, it must signal an EOS timestamp using the same mechanism.
+ * This is in addition to the timestamp of the last rendered frame, and should follow that
+ * frame.
*/
OMX_EventOutputRendered = 0x7F000001,
OMX_EventMax = 0x7FFFFFFF
diff --git a/include/media/openmax/OMX_VideoExt.h b/include/media/openmax/OMX_VideoExt.h
index 34c0405..3971bc5 100644
--- a/include/media/openmax/OMX_VideoExt.h
+++ b/include/media/openmax/OMX_VideoExt.h
@@ -203,10 +203,17 @@
OMX_BOOL bEnableLoopFilterAcrossSlices;
} OMX_VIDEO_SLICESEGMENTSTYPE;
-/** Structure to return timestamps of rendered output frames for tunneled components */
+/** Structure to return timestamps of rendered output frames as well as EOS
+ * for tunneled components.
+ */
typedef struct OMX_VIDEO_RENDEREVENTTYPE {
OMX_S64 nMediaTimeUs; // timestamp of rendered video frame
OMX_S64 nSystemTimeNs; // system monotonic time at the time frame was rendered
+ // Use INT64_MAX for nMediaTimeUs to signal that the EOS
+ // has been reached. In this case, nSystemTimeNs MUST be
+ // the system time when the last frame was rendered.
+ // This MUST be done in addition to returning (and
+ // following) the render information for the last frame.
} OMX_VIDEO_RENDEREVENTTYPE;
#ifdef __cplusplus
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
index 19298e2..e8f0981 100644
--- a/libs/binder/Android.mk
+++ b/libs/binder/Android.mk
@@ -37,6 +37,7 @@
PermissionCache.cpp \
ProcessState.cpp \
Static.cpp \
+ Status.cpp \
TextOutput.cpp \
LOCAL_PATH:= $(call my-dir)
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 56cde8a..a101d90 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -23,6 +23,7 @@
#include <binder/Binder.h>
#include <binder/BpBinder.h>
#include <binder/ProcessState.h>
+#include <binder/Status.h>
#include <binder/TextOutput.h>
#include <errno.h>
@@ -69,9 +70,6 @@
// Note: must be kept in sync with android/os/StrictMode.java's PENALTY_GATHER
#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
-// Note: must be kept in sync with android/os/Parcel.java's EX_HAS_REPLY_HEADER
-#define EX_HAS_REPLY_HEADER -128
-
// XXX This can be made public if we want to provide
// support for typed data.
struct small_flat_data
@@ -768,163 +766,37 @@
status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val)
{
- if (val.size() > std::numeric_limits<int32_t>::max()) {
- return BAD_VALUE;
- }
-
- status_t status = writeInt32(val.size());
-
- if (status != OK) {
- return status;
- }
-
- for (const auto& item : val) {
- status = writeInt32(item);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
+ return writeTypedVector(val, &Parcel::writeInt32);
}
status_t Parcel::writeInt64Vector(const std::vector<int64_t>& val)
{
- if (val.size() > std::numeric_limits<int32_t>::max()) {
- return BAD_VALUE;
- }
-
- status_t status = writeInt32(val.size());
-
- if (status != OK) {
- return status;
- }
-
- for (const auto& item : val) {
- status = writeInt64(item);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
+ return writeTypedVector(val, &Parcel::writeInt64);
}
status_t Parcel::writeFloatVector(const std::vector<float>& val)
{
- if (val.size() > std::numeric_limits<int32_t>::max()) {
- return BAD_VALUE;
- }
-
- status_t status = writeInt32(val.size());
-
- if (status != OK) {
- return status;
- }
-
- for (const auto& item : val) {
- status = writeFloat(item);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
+ return writeTypedVector(val, &Parcel::writeFloat);
}
status_t Parcel::writeDoubleVector(const std::vector<double>& val)
{
- if (val.size() > std::numeric_limits<int32_t>::max()) {
- return BAD_VALUE;
- }
-
- status_t status = writeInt32(val.size());
-
- if (status != OK) {
- return status;
- }
-
- for (const auto& item : val) {
- status = writeDouble(item);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
+ return writeTypedVector(val, &Parcel::writeDouble);
}
status_t Parcel::writeBoolVector(const std::vector<bool>& val)
{
- if (val.size() > std::numeric_limits<int32_t>::max()) {
- return BAD_VALUE;
- }
-
- status_t status = writeInt32(val.size());
-
- if (status != OK) {
- return status;
- }
-
- for (const auto& item : val) {
- status = writeBool(item);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
+ return writeTypedVector(val, &Parcel::writeBool);
}
status_t Parcel::writeCharVector(const std::vector<char16_t>& val)
{
- if (val.size() > std::numeric_limits<int32_t>::max()) {
- return BAD_VALUE;
- }
-
- status_t status = writeInt32(val.size());
-
- if (status != OK) {
- return status;
- }
-
- for (const auto& item : val) {
- status = writeChar(item);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
+ return writeTypedVector(val, &Parcel::writeChar);
}
status_t Parcel::writeString16Vector(const std::vector<String16>& val)
{
- if (val.size() > std::numeric_limits<int32_t>::max()) {
- return BAD_VALUE;
- }
-
- status_t status = writeInt32(val.size());
-
- if (status != OK) {
- return status;
- }
-
- for (const auto& item : val) {
- status = writeString16(item);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
+ return writeTypedVector(val, &Parcel::writeString16);
}
status_t Parcel::writeInt32(int32_t val)
@@ -1073,52 +945,11 @@
status_t Parcel::writeStrongBinderVector(const std::vector<sp<IBinder>>& val)
{
- if (val.size() > std::numeric_limits<int32_t>::max()) {
- return BAD_VALUE;
- }
-
- status_t status = writeInt32(val.size());
-
- if (status != OK) {
- return status;
- }
-
- for (const auto& item : val) {
- status = writeStrongBinder(item);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
+ return writeTypedVector(val, &Parcel::writeStrongBinder);
}
status_t Parcel::readStrongBinderVector(std::vector<sp<IBinder>>* val) const {
- val->clear();
-
- int32_t size;
- status_t status = readInt32(&size);
-
- if (status != OK) {
- return status;
- }
-
- if (size < 0) {
- return BAD_VALUE;
- }
-
- val->resize(size);
-
- for (auto& v : *val) {
- status = readStrongBinder(&v);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
+ return readTypedVector(val, &Parcel::readStrongBinder);
}
status_t Parcel::writeWeakBinder(const wp<IBinder>& val)
@@ -1126,6 +957,14 @@
return flatten_binder(ProcessState::self(), val, this);
}
+status_t Parcel::writeParcelable(const Parcelable& parcelable) {
+ status_t status = writeInt32(1); // parcelable is not null.
+ if (status != OK) {
+ return status;
+ }
+ return parcelable.writeToParcel(this);
+}
+
status_t Parcel::writeNativeHandle(const native_handle* handle)
{
if (!handle || handle->version != sizeof(native_handle))
@@ -1324,7 +1163,8 @@
status_t Parcel::writeNoException()
{
- return writeInt32(0);
+ binder::Status status;
+ return status.writeToParcel(this);
}
void Parcel::remove(size_t /*start*/, size_t /*amt*/)
@@ -1417,10 +1257,15 @@
return status;
}
- if (size < 0 || size_t(size) > dataAvail()) {
+ if (size < 0) {
+ status = UNEXPECTED_NULL;
+ return status;
+ }
+ if (size_t(size) > dataAvail()) {
status = BAD_VALUE;
return status;
}
+
const void* data = readInplace(size);
if (!data) {
status = BAD_VALUE;
@@ -1433,111 +1278,19 @@
}
status_t Parcel::readInt32Vector(std::vector<int32_t>* val) const {
- val->clear();
-
- int32_t size;
- status_t status = readInt32(&size);
-
- if (status != OK) {
- return status;
- }
-
- if (size < 0) {
- return BAD_VALUE;
- }
-
- val->resize(size);
-
- for (auto& v: *val) {
- status = readInt32(&v);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
+ return readTypedVector(val, &Parcel::readInt32);
}
status_t Parcel::readInt64Vector(std::vector<int64_t>* val) const {
- val->clear();
-
- int32_t size;
- status_t status = readInt32(&size);
-
- if (status != OK) {
- return status;
- }
-
- if (size < 0) {
- return BAD_VALUE;
- }
-
- val->resize(size);
-
- for (auto& v : *val) {
- status = readInt64(&v);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
+ return readTypedVector(val, &Parcel::readInt64);
}
status_t Parcel::readFloatVector(std::vector<float>* val) const {
- val->clear();
-
- int32_t size;
- status_t status = readInt32(&size);
-
- if (status != OK) {
- return status;
- }
-
- if (size < 0) {
- return BAD_VALUE;
- }
-
- val->resize(size);
-
- for (auto& v : *val) {
- status = readFloat(&v);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
+ return readTypedVector(val, &Parcel::readFloat);
}
status_t Parcel::readDoubleVector(std::vector<double>* val) const {
- val->clear();
-
- int32_t size;
- status_t status = readInt32(&size);
-
- if (status != OK) {
- return status;
- }
-
- if (size < 0) {
- return BAD_VALUE;
- }
-
- val->resize(size);
-
- for (auto& v : *val) {
- status = readDouble(&v);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
+ return readTypedVector(val, &Parcel::readDouble);
}
status_t Parcel::readBoolVector(std::vector<bool>* val) const {
@@ -1551,7 +1304,7 @@
}
if (size < 0) {
- return BAD_VALUE;
+ return UNEXPECTED_NULL;
}
val->resize(size);
@@ -1573,61 +1326,11 @@
}
status_t Parcel::readCharVector(std::vector<char16_t>* val) const {
- val->clear();
-
- int32_t size;
- status_t status = readInt32(&size);
-
- if (status != OK) {
- return status;
- }
-
- if (size < 0) {
- return BAD_VALUE;
- }
-
- val->resize(size);
-
- for (auto& v : *val) {
- status = readChar(&v);
-
- if (status != OK) {
- return status;
- }
- }
-
- return OK;
+ return readTypedVector(val, &Parcel::readChar);
}
status_t Parcel::readString16Vector(std::vector<String16>* val) const {
- val->clear();
-
- int32_t size;
- status_t status = readInt32(&size);
-
- if (status != OK) {
- return status;
- }
-
- if (size < 0) {
- return BAD_VALUE;
- }
-
- val->reserve(size);
-
- while (size-- > 0) {
- const char16_t *data;
- size_t size;
- data = readString16Inplace(&size);
-
- if (data == nullptr) {
- return UNKNOWN_ERROR;
- }
-
- val->emplace_back(data, size);
- }
-
- return OK;
+ return readTypedVector(val, &Parcel::readString16);
}
@@ -1834,7 +1537,7 @@
return 0;
} else {
*pArg = String16();
- return UNKNOWN_ERROR;
+ return UNEXPECTED_NULL;
}
}
@@ -1872,20 +1575,23 @@
return val;
}
+status_t Parcel::readParcelable(Parcelable* parcelable) const {
+ int32_t have_parcelable = 0;
+ status_t status = readInt32(&have_parcelable);
+ if (status != OK) {
+ return status;
+ }
+ if (!have_parcelable) {
+ return UNEXPECTED_NULL;
+ }
+ return parcelable->readFromParcel(this);
+}
+
int32_t Parcel::readExceptionCode() const
{
- int32_t exception_code = readAligned<int32_t>();
- if (exception_code == EX_HAS_REPLY_HEADER) {
- int32_t header_start = dataPosition();
- int32_t header_size = readAligned<int32_t>();
- // Skip over fat responses headers. Not used (or propagated) in
- // native code
- setDataPosition(header_start + header_size);
- // And fat response headers are currently only used when there are no
- // exceptions, so return no error:
- return 0;
- }
- return exception_code;
+ binder::Status status;
+ status.readFromParcel(*this);
+ return status.exceptionCode();
}
native_handle* Parcel::readNativeHandle() const
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
new file mode 100644
index 0000000..41fff3d
--- /dev/null
+++ b/libs/binder/Status.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/Status.h>
+
+namespace android {
+namespace binder {
+
+Status Status::fromExceptionCode(int32_t exception_code) {
+ return Status(exception_code, "");
+}
+
+Status Status::fromStatusT(status_t status) {
+ Status ret;
+ ret.setFromStatusT(status);
+ return ret;
+}
+
+Status Status::ok() {
+ return Status();
+}
+
+Status::Status(int32_t exception_code, const String8& message)
+ : mException(exception_code),
+ mMessage(message) {}
+
+Status::Status(int32_t exception_code, const char* message)
+ : mException(exception_code),
+ mMessage(message) {}
+
+status_t Status::readFromParcel(const Parcel& parcel) {
+ status_t status = parcel.readInt32(&mException);
+ if (status != OK) {
+ setFromStatusT(status);
+ return status;
+ }
+
+ // Skip over fat response headers. Not used (or propagated) in native code.
+ if (mException == EX_HAS_REPLY_HEADER) {
+ // Note that the header size includes the 4 byte size field.
+ const int32_t header_start = parcel.dataPosition();
+ int32_t header_size;
+ status = parcel.readInt32(&header_size);
+ if (status != OK) {
+ setFromStatusT(status);
+ return status;
+ }
+ parcel.setDataPosition(header_start + header_size);
+ // And fat response headers are currently only used when there are no
+ // exceptions, so act like there was no error.
+ mException = EX_NONE;
+ }
+
+ if (mException == EX_NONE) {
+ return status;
+ }
+
+ // The remote threw an exception. Get the message back.
+ mMessage = String8(parcel.readString16());
+
+ return status;
+}
+
+status_t Status::writeToParcel(Parcel* parcel) const {
+ status_t status = parcel->writeInt32(mException);
+ if (status != OK) { return status; }
+ if (mException == EX_NONE) {
+ // We have no more information to write.
+ return status;
+ }
+ status = parcel->writeString16(String16(mMessage));
+ return status;
+}
+
+void Status::setFromStatusT(status_t status) {
+ switch (status) {
+ case NO_ERROR:
+ mException = EX_NONE;
+ mMessage.clear();
+ break;
+ case UNEXPECTED_NULL:
+ mException = EX_NULL_POINTER;
+ mMessage.setTo("Unexpected null reference in Parcel");
+ break;
+ default:
+ mException = EX_TRANSACTION_FAILED;
+ mMessage.setTo("Transaction failed");
+ break;
+ }
+}
+
+void Status::setException(int32_t ex, const String8& message) {
+ mException = ex;
+ mMessage.setTo(message);
+}
+
+void Status::getException(int32_t* returned_exception,
+ String8* returned_message) const {
+ if (returned_exception) {
+ *returned_exception = mException;
+ }
+ if (returned_message) {
+ returned_message->setTo(mMessage);
+ }
+}
+
+String8 Status::toString8() const {
+ String8 ret;
+ if (mException == EX_NONE) {
+ ret.append("No error");
+ } else {
+ ret.appendFormat("Status(%d): '", mException);
+ ret.append(String8(mMessage));
+ ret.append("'");
+ }
+ return ret;
+}
+
+} // namespace binder
+} // namespace android
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 0f58f96..e593a72 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -68,7 +68,9 @@
* -1 -> not running inside the emulator
* 0 -> running inside the emulator, but GPU emulation not supported
* 1 -> running inside the emulator, GPU emulation is supported
- * through the "emulation" config.
+ * through the "emulation" host-side OpenGL ES implementation.
+ * 2 -> running inside the emulator, GPU emulation is supported
+ * through a guest-side vendor driver's OpenGL ES implementation.
*/
static int
checkGlesEmulationStatus(void)
@@ -275,6 +277,30 @@
public:
static String8 find(const char* kind) {
String8 result;
+ int emulationStatus = checkGlesEmulationStatus();
+ switch (emulationStatus) {
+ case 0:
+ ALOGD("Emulator without GPU support detected. "
+ "Fallback to legacy software renderer.");
+#if defined(__LP64__)
+ result.setTo("/system/lib64/egl/libGLES_android.so");
+#else
+ result.setTo("/system/lib/egl/libGLES_android.so");
+#endif
+ return result;
+ case 1:
+ // Use host-side OpenGL through the "emulation" library
+#if defined(__LP64__)
+ result.appendFormat("/system/lib64/egl/lib%s_emulation.so", kind);
+#else
+ result.appendFormat("/system/lib/egl/lib%s_emulation.so", kind);
+#endif
+ return result;
+ default:
+ // Not in emulator, or use other guest-side implementation
+ break;
+ }
+
String8 pattern;
pattern.appendFormat("lib%s", kind);
const char* const searchPaths[] = {
@@ -319,20 +345,6 @@
private:
static bool find(String8& result,
const String8& pattern, const char* const search, bool exact) {
-
- // in the emulator case, we just return the hardcoded name
- // of the software renderer.
- if (checkGlesEmulationStatus() == 0) {
- ALOGD("Emulator without GPU support detected. "
- "Fallback to software renderer.");
-#if defined(__LP64__)
- result.setTo("/system/lib64/egl/libGLES_android.so");
-#else
- result.setTo("/system/lib/egl/libGLES_android.so");
-#endif
- return true;
- }
-
if (exact) {
String8 absolutePath;
absolutePath.appendFormat("%s/%s.so", search, pattern.string());
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index ad53226..2b6e0ec 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -86,7 +86,8 @@
mQueueItemCondition(),
mQueueItems(),
mLastFrameNumberReceived(0),
- mUpdateTexImageFailed(false)
+ mUpdateTexImageFailed(false),
+ mSingleBufferMode(false)
{
mCurrentCrop.makeInvalid();
mFlinger->getRenderEngine().genTextures(1, &mTextureName);
@@ -952,12 +953,13 @@
// then it is expired or otherwise invalid. Allow this transaction
// to be applied as per normal (no synchronization).
mCurrentState.handle = nullptr;
+ } else {
+ auto syncPoint = std::make_shared<SyncPoint>(
+ mCurrentState.frameNumber);
+ handleLayer->addSyncPoint(syncPoint);
+ mRemoteSyncPoints.push_back(std::move(syncPoint));
}
- auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.frameNumber);
- handleLayer->addSyncPoint(syncPoint);
- mRemoteSyncPoints.push_back(std::move(syncPoint));
-
// Wake us up to check if the frame has been received
setTransactionFlags(eTransactionNeeded);
}
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
index eb9bd25..1d6e20f 100644
--- a/services/surfaceflinger/surfaceflinger.rc
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -3,4 +3,4 @@
user system
group graphics drmrpc readproc
onrestart restart zygote
- writepid /dev/cpuset/system-background/tasks
+ writepid /dev/cpuset/system-background/tasks /sys/fs/cgroup/stune/foreground/tasks