summaryrefslogtreecommitdiffstats
path: root/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'cmds')
-rw-r--r--cmds/atrace/atrace.cpp67
-rw-r--r--cmds/bugreport/bugreport.c2
-rw-r--r--cmds/dumpstate/dumpstate.c133
-rw-r--r--cmds/dumpstate/dumpstate.h14
-rw-r--r--cmds/dumpstate/utils.c100
-rw-r--r--cmds/flatland/Android.mk4
-rw-r--r--cmds/flatland/GLHelper.cpp10
-rw-r--r--cmds/flatland/Main.cpp6
-rw-r--r--cmds/installd/commands.c271
-rw-r--r--cmds/installd/installd.c47
-rw-r--r--cmds/installd/installd.h8
-rw-r--r--cmds/installd/tests/installd_utils_test.cpp58
-rw-r--r--cmds/installd/utils.c78
-rw-r--r--cmds/screenshot/Android.mk12
-rw-r--r--cmds/screenshot/screenshot.c171
-rw-r--r--cmds/servicemanager/service_manager.c146
16 files changed, 668 insertions, 459 deletions
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 3461e38..9e5c910 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -40,7 +40,7 @@ using namespace android;
#define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0])))
-enum { MAX_SYS_FILES = 8 };
+enum { MAX_SYS_FILES = 10 };
const char* k_traceTagsProperty = "debug.atrace.tags.enableflags";
const char* k_traceAppCmdlineProperty = "debug.atrace.app_cmdlines";
@@ -77,18 +77,24 @@ static const TracingCategory k_categories[] = {
{ "webview", "WebView", ATRACE_TAG_WEBVIEW, { } },
{ "wm", "Window Manager", ATRACE_TAG_WINDOW_MANAGER, { } },
{ "am", "Activity Manager", ATRACE_TAG_ACTIVITY_MANAGER, { } },
+ { "sync", "Sync Manager", ATRACE_TAG_SYNC_MANAGER, { } },
{ "audio", "Audio", ATRACE_TAG_AUDIO, { } },
{ "video", "Video", ATRACE_TAG_VIDEO, { } },
{ "camera", "Camera", ATRACE_TAG_CAMERA, { } },
{ "hal", "Hardware Modules", ATRACE_TAG_HAL, { } },
+ { "app", "Application", ATRACE_TAG_APP, { } },
{ "res", "Resource Loading", ATRACE_TAG_RESOURCES, { } },
{ "dalvik", "Dalvik VM", ATRACE_TAG_DALVIK, { } },
{ "rs", "RenderScript", ATRACE_TAG_RS, { } },
{ "bionic", "Bionic C Library", ATRACE_TAG_BIONIC, { } },
+ { "power", "Power Management", ATRACE_TAG_POWER, { } },
{ "sched", "CPU Scheduling", 0, {
{ REQ, "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
{ REQ, "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
} },
+ { "irq", "IRQ Events", 0, {
+ { REQ, "/sys/kernel/debug/tracing/events/irq/enable" },
+ } },
{ "freq", "CPU Frequency", 0, {
{ REQ, "/sys/kernel/debug/tracing/events/power/cpu_frequency/enable" },
{ OPT, "/sys/kernel/debug/tracing/events/power/clock_set_rate/enable" },
@@ -100,6 +106,12 @@ static const TracingCategory k_categories[] = {
{ REQ, "/sys/kernel/debug/tracing/events/power/cpu_idle/enable" },
} },
{ "disk", "Disk I/O", 0, {
+ { REQ, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_enter/enable" },
+ { REQ, "/sys/kernel/debug/tracing/events/f2fs/f2fs_sync_file_exit/enable" },
+ { REQ, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_begin/enable" },
+ { REQ, "/sys/kernel/debug/tracing/events/f2fs/f2fs_write_end/enable" },
+ { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_begin/enable" },
+ { REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_da_write_end/enable" },
{ REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_enter/enable" },
{ REQ, "/sys/kernel/debug/tracing/events/ext4/ext4_sync_file_exit/enable" },
{ REQ, "/sys/kernel/debug/tracing/events/block/block_rq_issue/enable" },
@@ -117,6 +129,12 @@ static const TracingCategory k_categories[] = {
{ "workq", "Kernel Workqueues", 0, {
{ REQ, "/sys/kernel/debug/tracing/events/workqueue/enable" },
} },
+ { "memreclaim", "Kernel Memory Reclaim", 0, {
+ { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable" },
+ { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable" },
+ { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable" },
+ { REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable" },
+ } },
};
/* Command line options */
@@ -323,11 +341,56 @@ static bool setTraceBufferSizeKB(int size)
return writeStr(k_traceBufferSizePath, str);
}
+// Read the trace_clock sysfs file and return true if it matches the requested
+// value. The trace_clock file format is:
+// local [global] counter uptime perf
+static bool isTraceClock(const char *mode)
+{
+ int fd = open(k_traceClockPath, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "error opening %s: %s (%d)\n", k_traceClockPath,
+ strerror(errno), errno);
+ return false;
+ }
+
+ char buf[4097];
+ ssize_t n = read(fd, buf, 4096);
+ close(fd);
+ if (n == -1) {
+ fprintf(stderr, "error reading %s: %s (%d)\n", k_traceClockPath,
+ strerror(errno), errno);
+ return false;
+ }
+ buf[n] = '\0';
+
+ char *start = strchr(buf, '[');
+ if (start == NULL) {
+ return false;
+ }
+ start++;
+
+ char *end = strchr(start, ']');
+ if (end == NULL) {
+ return false;
+ }
+ *end = '\0';
+
+ return strcmp(mode, start) == 0;
+}
+
// Enable or disable the kernel's use of the global clock. Disabling the global
// clock will result in the kernel using a per-CPU local clock.
+// Any write to the trace_clock sysfs file will reset the buffer, so only
+// update it if the requested value is not the current value.
static bool setGlobalClockEnable(bool enable)
{
- return writeStr(k_traceClockPath, enable ? "global" : "local");
+ const char *clock = enable ? "global" : "local";
+
+ if (isTraceClock(clock)) {
+ return true;
+ }
+
+ return writeStr(k_traceClockPath, clock);
}
static bool setPrintTgidEnableIfPresent(bool enable)
diff --git a/cmds/bugreport/bugreport.c b/cmds/bugreport/bugreport.c
index 4a0b511..11e9057 100644
--- a/cmds/bugreport/bugreport.c
+++ b/cmds/bugreport/bugreport.c
@@ -29,7 +29,7 @@ int main(int argc, char *argv[]) {
property_set("ctl.start", "dumpstate");
/* socket will not be available until service starts */
- for (i = 0; i < 10; i++) {
+ for (i = 0; i < 20; i++) {
s = socket_local_client("dumpstate",
ANDROID_SOCKET_NAMESPACE_RESERVED,
SOCK_STREAM);
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 913cedf..f142095 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -20,13 +20,13 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/capability.h>
+#include <sys/prctl.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <unistd.h>
-#include <sys/capability.h>
-#include <linux/prctl.h>
#include <cutils/properties.h>
@@ -45,6 +45,36 @@ static char screenshot_path[PATH_MAX] = "";
#define PSTORE_LAST_KMSG "/sys/fs/pstore/console-ramoops"
+#define TOMBSTONE_DIR "/data/tombstones"
+#define TOMBSTONE_FILE_PREFIX TOMBSTONE_DIR "/tombstone_"
+/* Can accomodate a tombstone number up to 9999. */
+#define TOMBSTONE_MAX_LEN (sizeof(TOMBSTONE_FILE_PREFIX) + 4)
+#define NUM_TOMBSTONES 10
+
+typedef struct {
+ char name[TOMBSTONE_MAX_LEN];
+ int fd;
+} tombstone_data_t;
+
+static tombstone_data_t tombstone_data[NUM_TOMBSTONES];
+
+/* Get the fds of any tombstone that was modified in the last half an hour. */
+static void get_tombstone_fds(tombstone_data_t data[NUM_TOMBSTONES]) {
+ time_t thirty_minutes_ago = time(NULL) - 60*30;
+ for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
+ snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
+ int fd = open(data[i].name, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+ struct stat st;
+ if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
+ (time_t) st.st_mtime >= thirty_minutes_ago) {
+ data[i].fd = fd;
+ } else {
+ close(fd);
+ data[i].fd = -1;
+ }
+ }
+}
+
/* dumps the current system state to stdout */
static void dumpstate() {
time_t now = time(NULL);
@@ -89,11 +119,11 @@ static void dumpstate() {
dump_file("BUDDYINFO", "/proc/buddyinfo");
dump_file("FRAGMENTATION INFO", "/d/extfrag/unusable_index");
-
dump_file("KERNEL WAKELOCKS", "/proc/wakelocks");
dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
dump_file("KERNEL SYNC", "/d/sync");
+ dump_file("KERNEL BLUEDROID", "/d/bluedroid");
run_command("PROCESSES", 10, "ps", "-P", NULL);
run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL);
@@ -103,6 +133,8 @@ static void dumpstate() {
do_dmesg();
run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
+ for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
+ for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
if (screenshot_path[0]) {
ALOGI("taking screenshot\n");
@@ -110,15 +142,11 @@ static void dumpstate() {
ALOGI("wrote screenshot: %s\n", screenshot_path);
}
- for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
- for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS");
-
// dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
run_command("SYSTEM LOG", 20, "logcat", "-v", "threadtime", "-d", "*:v", NULL);
run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL);
run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL);
-
/* show the traces we collected in main(), if that was done */
if (dump_traces_path != NULL) {
dump_file("VM TRACES JUST NOW", dump_traces_path);
@@ -130,10 +158,13 @@ static void dumpstate() {
property_get("dalvik.vm.stack-trace-file", anr_traces_path, "");
if (!anr_traces_path[0]) {
printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
- } else if (stat(anr_traces_path, &st)) {
- printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
} else {
- dump_file("VM TRACES AT LAST ANR", anr_traces_path);
+ int fd = open(anr_traces_path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+ if (fd < 0) {
+ printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
+ } else {
+ dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_path, fd);
+ }
}
/* slow traces for slow operations */
@@ -154,15 +185,24 @@ static void dumpstate() {
}
}
+ int dumped = 0;
+ for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
+ if (tombstone_data[i].fd != -1) {
+ dumped = 1;
+ dump_file_from_fd("TOMBSTONE", tombstone_data[i].name, tombstone_data[i].fd);
+ tombstone_data[i].fd = -1;
+ }
+ }
+ if (!dumped) {
+ printf("*** NO TOMBSTONES to dump in %s\n\n", TOMBSTONE_DIR);
+ }
+
dump_file("NETWORK DEV INFO", "/proc/net/dev");
dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
- dump_file("NETWORK ROUTES", "/proc/net/route");
- dump_file("NETWORK ROUTES IPV6", "/proc/net/ipv6_route");
-
if (!stat(PSTORE_LAST_KMSG, &st)) {
/* Also TODO: Make console-ramoops CAP_SYSLOG protected. */
dump_file("LAST KMSG", PSTORE_LAST_KMSG);
@@ -174,18 +214,22 @@ static void dumpstate() {
dump_file("LAST PANIC CONSOLE", "/data/dontpanic/apanic_console");
dump_file("LAST PANIC THREADS", "/data/dontpanic/apanic_threads");
- run_command("SYSTEM SETTINGS", 20, SU_PATH, "root", "sqlite3",
- "/data/data/com.android.providers.settings/databases/settings.db",
- "pragma user_version; select * from system; select * from secure; select * from global;", NULL);
+ for_each_userid(do_dump_settings, NULL);
/* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
run_command("NETWORK INTERFACES", 10, SU_PATH, "root", "netcfg", NULL);
+
+ run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
+ run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
+
run_command("IP RULES", 10, "ip", "rule", "show", NULL);
run_command("IP RULES v6", 10, "ip", "-6", "rule", "show", NULL);
dump_route_tables();
- dump_file("ARP CACHE", "/proc/net/arp");
+ run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
+ run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
+
run_command("IPTABLES", 10, SU_PATH, "root", "iptables", "-L", "-nvx", NULL);
run_command("IP6TABLES", 10, SU_PATH, "root", "ip6tables", "-L", "-nvx", NULL);
run_command("IPTABLE NAT", 10, SU_PATH, "root", "iptables", "-t", "nat", "-L", "-nvx", NULL);
@@ -332,8 +376,13 @@ static void usage() {
}
static void sigpipe_handler(int n) {
- (void)n;
- exit(EXIT_FAILURE);
+ // don't complain to stderr or stdout
+ _exit(EXIT_FAILURE);
+}
+
+static void vibrate(FILE* vibrator, int ms) {
+ fprintf(vibrator, "%d\n", ms);
+ fflush(vibrator);
}
int main(int argc, char *argv[]) {
@@ -342,8 +391,6 @@ int main(int argc, char *argv[]) {
int do_compress = 0;
int do_vibrate = 1;
char* use_outfile = 0;
- char* begin_sound = 0;
- char* end_sound = 0;
int use_socket = 0;
int do_fb = 0;
int do_broadcast = 0;
@@ -356,8 +403,10 @@ int main(int argc, char *argv[]) {
// correct program.
return execl("/system/bin/bugreport", "/system/bin/bugreport", NULL);
}
+
ALOGI("begin\n");
+ /* clear SIGPIPE handler */
memset(&sigact, 0, sizeof(sigact));
sigact.sa_handler = sigpipe_handler;
sigaction(SIGPIPE, &sigact, NULL);
@@ -370,15 +419,11 @@ int main(int argc, char *argv[]) {
fclose(oom_adj);
}
- /* very first thing, collect stack traces from Dalvik and native processes (needs root) */
- dump_traces_path = dump_traces();
-
+ /* parse arguments */
int c;
- while ((c = getopt(argc, argv, "b:de:ho:svqzpB")) != -1) {
+ while ((c = getopt(argc, argv, "dho:svqzpB")) != -1) {
switch (c) {
- case 'b': begin_sound = optarg; break;
case 'd': do_add_date = 1; break;
- case 'e': end_sound = optarg; break;
case 'o': use_outfile = optarg; break;
case 's': use_socket = 1; break;
case 'v': break; // compatibility no-op
@@ -393,11 +438,14 @@ int main(int argc, char *argv[]) {
}
}
+ /* open the vibrator before dropping root */
FILE *vibrator = 0;
if (do_vibrate) {
- /* open the vibrator before dropping root */
vibrator = fopen("/sys/class/timed_output/vibrator/enable", "w");
- if (vibrator) fcntl(fileno(vibrator), F_SETFD, FD_CLOEXEC);
+ if (vibrator) {
+ fcntl(fileno(vibrator), F_SETFD, FD_CLOEXEC);
+ vibrate(vibrator, 150);
+ }
}
/* read /proc/cmdline before dropping root */
@@ -407,6 +455,13 @@ int main(int argc, char *argv[]) {
fclose(cmdline);
}
+ /* collect stack traces from Dalvik and native processes (needs root) */
+ dump_traces_path = dump_traces();
+
+ /* Get the tombstone fds here while we are running as root. */
+ get_tombstone_fds(tombstone_data);
+
+ /* ensure we will keep capabilities when we drop root */
if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
return -1;
@@ -445,6 +500,7 @@ int main(int argc, char *argv[]) {
return -1;
}
+ /* redirect output if needed */
char path[PATH_MAX], tmp_path[PATH_MAX];
pid_t gzip_pid = -1;
@@ -469,22 +525,12 @@ int main(int argc, char *argv[]) {
gzip_pid = redirect_to_file(stdout, tmp_path, do_compress);
}
- if (begin_sound) {
- play_sound(begin_sound);
- } else if (vibrator) {
- fputs("150", vibrator);
- fflush(vibrator);
- }
-
dumpstate();
- if (end_sound) {
- play_sound(end_sound);
- } else if (vibrator) {
- int i;
- for (i = 0; i < 3; i++) {
- fputs("75\n", vibrator);
- fflush(vibrator);
+ /* done */
+ if (vibrator) {
+ for (int i = 0; i < 3; i++) {
+ vibrate(vibrator, 75);
usleep((75 + 50) * 1000);
}
fclose(vibrator);
@@ -501,6 +547,7 @@ int main(int argc, char *argv[]) {
fprintf(stderr, "rename(%s, %s): %s\n", tmp_path, path, strerror(errno));
}
+ /* 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",
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 6906dcf..53bfff6 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -26,9 +26,13 @@
typedef void (for_each_pid_func)(int, const char *);
typedef void (for_each_tid_func)(int, int, const char *);
+typedef void (for_each_userid_func)(int);
/* prints the contents of a file */
-int dump_file(const char *title, const char* path);
+int dump_file(const char *title, const char *path);
+
+/* prints the contents of the fd */
+int dump_file_from_fd(const char *title, const char *path, int fd);
/* 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, ...);
@@ -51,6 +55,9 @@ void for_each_pid(for_each_pid_func func, const char *header);
/* for each thread in the system, run the specified function */
void for_each_tid(for_each_tid_func func, const char *header);
+/* for each user id in the system, run the specified function */
+void for_each_userid(for_each_userid_func func, const char *header);
+
/* Displays a blocked processes in-kernel wait channel */
void show_wchan(int pid, int tid, const char *name);
@@ -60,11 +67,14 @@ void do_showmap(int pid, const char *name);
/* Gets the dmesg output for the kernel */
void do_dmesg();
+/* Dumps settings for a given user id */
+void do_dump_settings(int userid);
+
/* Prints the contents of all the routing tables, both IPv4 and IPv6. */
void dump_route_tables();
/* Play a sound via Stagefright */
-void play_sound(const char* path);
+void play_sound(const char *path);
/* Implemented by libdumpstate_board to dump board-specific info */
void dumpstate_board();
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index b6110c6..e3042eb 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -42,6 +42,8 @@
#include "dumpstate.h"
+static const int64_t NANOS_PER_SEC = 1000000000;
+
/* list of native processes to include in the native dumps */
static const char* native_processes_to_dump[] = {
"/system/bin/drmserver",
@@ -51,6 +53,29 @@ static const char* native_processes_to_dump[] = {
NULL,
};
+void for_each_userid(void (*func)(int), const char *header) {
+ DIR *d;
+ struct dirent *de;
+
+ if (header) printf("\n------ %s ------\n", header);
+ func(0);
+
+ if (!(d = opendir("/data/system/users"))) {
+ printf("Failed to open /data/system/users (%s)\n", strerror(errno));
+ return;
+ }
+
+ while ((de = readdir(d))) {
+ int userid;
+ if (de->d_type != DT_DIR || !(userid = atoi(de->d_name))) {
+ continue;
+ }
+ func(userid);
+ }
+
+ closedir(d);
+}
+
static void __for_each_pid(void (*helper)(int, const char *, void *), const char *header, void *arg) {
DIR *d;
struct dirent *de;
@@ -175,6 +200,22 @@ out_close:
return;
}
+void do_dump_settings(int userid) {
+ char title[255];
+ char dbpath[255];
+ char sql[255];
+ sprintf(title, "SYSTEM SETTINGS (user %d)", userid);
+ if (userid == 0) {
+ strcpy(dbpath, "/data/data/com.android.providers.settings/databases/settings.db");
+ strcpy(sql, "pragma user_version; select * from system; select * from secure; select * from global;");
+ } else {
+ sprintf(dbpath, "/data/system/users/%d/settings.db", userid);
+ strcpy(sql, "pragma user_version; select * from system; select * from secure;");
+ }
+ run_command(title, 20, SU_PATH, "root", "sqlite3", dbpath, sql, NULL);
+ return;
+}
+
void do_dmesg() {
printf("------ KERNEL LOG (dmesg) ------\n");
/* Get size of kernel buffer */
@@ -210,8 +251,7 @@ void do_showmap(int pid, const char *name) {
}
/* prints the contents of a file */
-int dump_file(const char *title, const char* path) {
- char buffer[32768];
+int dump_file(const char *title, const char *path) {
int fd = open(path, O_RDONLY);
if (fd < 0) {
int err = errno;
@@ -220,6 +260,11 @@ int dump_file(const char *title, const char* path) {
if (title) printf("\n");
return -1;
}
+ return dump_file_from_fd(title, path, fd);
+}
+
+int dump_file_from_fd(const char *title, const char *path, int fd) {
+ char buffer[32768];
if (title) printf("------ %s (%s", title, path);
@@ -243,17 +288,23 @@ int dump_file(const char *title, const char* path) {
}
if (ret <= 0) break;
}
-
close(fd);
+
if (!newline) printf("\n");
if (title) printf("\n");
return 0;
}
+static int64_t nanotime() {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (int64_t)ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec;
+}
+
/* forks a command and waits for it to finish */
int run_command(const char *title, int timeout_seconds, const char *command, ...) {
fflush(stdout);
- clock_t start = clock();
+ int64_t start = nanotime();
pid_t pid = fork();
/* handle error case */
@@ -270,6 +321,12 @@ int run_command(const char *title, int timeout_seconds, const char *command, ...
/* make sure the child dies when dumpstate dies */
prctl(PR_SET_PDEATHSIG, SIGKILL);
+ /* just ignore SIGPIPE, will go down with parent's */
+ struct sigaction sigact;
+ memset(&sigact, 0, sizeof(sigact));
+ sigact.sa_handler = SIG_IGN;
+ sigaction(SIGPIPE, &sigact, NULL);
+
va_list ap;
va_start(ap, command);
if (title) printf("------ %s (%s", title, command);
@@ -291,19 +348,19 @@ int run_command(const char *title, int timeout_seconds, const char *command, ...
for (;;) {
int status;
pid_t p = waitpid(pid, &status, WNOHANG);
- float elapsed = (float) (clock() - start) / CLOCKS_PER_SEC;
+ int64_t elapsed = nanotime() - start;
if (p == pid) {
if (WIFSIGNALED(status)) {
printf("*** %s: Killed by signal %d\n", command, WTERMSIG(status));
} else if (WIFEXITED(status) && WEXITSTATUS(status) > 0) {
printf("*** %s: Exit code %d\n", command, WEXITSTATUS(status));
}
- if (title) printf("[%s: %.1fs elapsed]\n\n", command, elapsed);
+ if (title) printf("[%s: %.3fs elapsed]\n\n", command, (float)elapsed / NANOS_PER_SEC);
return status;
}
- if (timeout_seconds && elapsed > timeout_seconds) {
- printf("*** %s: Timed out after %.1fs (killing pid %d)\n", command, elapsed, pid);
+ if (timeout_seconds && elapsed / NANOS_PER_SEC > timeout_seconds) {
+ printf("*** %s: Timed out after %ds (killing pid %d)\n", command, (int) elapsed, pid);
kill(pid, SIGTERM);
return -1;
}
@@ -526,21 +583,22 @@ const char *dump_traces() {
}
data[len] = '\0';
- if (!strcmp(data, "/system/bin/app_process")) {
+ if (!strncmp(data, "/system/bin/app_process", strlen("/system/bin/app_process"))) {
/* skip zygote -- it won't dump its stack anyway */
snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
- int fd = open(path, O_RDONLY);
- len = read(fd, data, sizeof(data) - 1);
- close(fd);
+ int cfd = open(path, O_RDONLY);
+ len = read(cfd, data, sizeof(data) - 1);
+ close(cfd);
if (len <= 0) {
continue;
}
data[len] = '\0';
- if (!strcmp(data, "zygote")) {
+ if (!strncmp(data, "zygote", strlen("zygote"))) {
continue;
}
++dalvik_found;
+ int64_t start = nanotime();
if (kill(pid, SIGQUIT)) {
fprintf(stderr, "kill(%d, SIGQUIT): %s\n", pid, strerror(errno));
continue;
@@ -557,12 +615,24 @@ const char *dump_traces() {
struct inotify_event ie;
read(ifd, &ie, sizeof(ie));
}
+
+ if (lseek(fd, 0, SEEK_END) < 0) {
+ fprintf(stderr, "lseek: %s\n", strerror(errno));
+ } else {
+ snprintf(data, sizeof(data), "[dump dalvik stack %d: %.3fs elapsed]\n",
+ pid, (float)(nanotime() - start) / NANOS_PER_SEC);
+ write(fd, data, strlen(data));
+ }
} else if (should_dump_native_traces(data)) {
/* dump native process if appropriate */
if (lseek(fd, 0, SEEK_END) < 0) {
fprintf(stderr, "lseek: %s\n", strerror(errno));
} else {
+ int64_t start = nanotime();
dump_backtrace_to_file(pid, fd);
+ snprintf(data, sizeof(data), "[dump native stack %d: %.3fs elapsed]\n",
+ pid, (float)(nanotime() - start) / NANOS_PER_SEC);
+ write(fd, data, strlen(data));
}
}
}
@@ -590,10 +660,6 @@ error_close_fd:
return result;
}
-void play_sound(const char* path) {
- run_command(NULL, 5, "/system/bin/stagefright", "-o", "-a", path, NULL);
-}
-
void dump_route_tables() {
const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
dump_file("RT_TABLES", RT_TABLES_PATH);
diff --git a/cmds/flatland/Android.mk b/cmds/flatland/Android.mk
index d9478fe..c295167 100644
--- a/cmds/flatland/Android.mk
+++ b/cmds/flatland/Android.mk
@@ -13,7 +13,9 @@ LOCAL_MODULE:= flatland
LOCAL_MODULE_TAGS := tests
LOCAL_MODULE_PATH := $(local_target_dir)
-
+LOCAL_MULTILIB := both
+LOCAL_MODULE_STEM_32 := flatland
+LOCAL_MODULE_STEM_64 := flatland64
LOCAL_SHARED_LIBRARIES := \
libEGL \
libGLESv2 \
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 05d082b..3155766 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -201,14 +201,16 @@ bool GLHelper::getShaderProgram(const char* name, GLuint* outPgm) {
bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h,
sp<GLConsumer>* glConsumer, EGLSurface* surface) {
- sp<BufferQueue> bq = new BufferQueue(mGraphicBufferAlloc);
- sp<GLConsumer> glc = new GLConsumer(bq, name,
- GL_TEXTURE_EXTERNAL_OES, false);
+ sp<IGraphicBufferProducer> producer;
+ sp<IGraphicBufferConsumer> consumer;
+ BufferQueue::createBufferQueue(&producer, &consumer, mGraphicBufferAlloc);
+ sp<GLConsumer> glc = new GLConsumer(consumer, name,
+ GL_TEXTURE_EXTERNAL_OES, false, true);
glc->setDefaultBufferSize(w, h);
glc->setDefaultMaxBufferCount(3);
glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
- sp<ANativeWindow> anw = new Surface(bq);
+ sp<ANativeWindow> anw = new Surface(producer);
EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL);
if (s == EGL_NO_SURFACE) {
fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp
index c0e5b3d..866203f 100644
--- a/cmds/flatland/Main.cpp
+++ b/cmds/flatland/Main.cpp
@@ -73,7 +73,7 @@ static const BenchmarkDesc benchmarks[] = {
},
},
- { "3:2 Single Static Window",
+ { "4:3 Single Static Window",
2048, 1536, { 1536 },
{
{ // Window
@@ -117,7 +117,7 @@ static const BenchmarkDesc benchmarks[] = {
},
},
- { "3:2 App -> Home Transition",
+ { "4:3 App -> Home Transition",
2048, 1536, { 1536 },
{
{ // Wallpaper
@@ -173,7 +173,7 @@ static const BenchmarkDesc benchmarks[] = {
},
},
- { "3:2 SurfaceView -> Home Transition",
+ { "4:3 SurfaceView -> Home Transition",
2048, 1536, { 1536 },
{
{ // Wallpaper
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 41a8f30..fc3972e 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -17,6 +17,7 @@
#include <inttypes.h>
#include <sys/capability.h>
#include "installd.h"
+#include <cutils/sched_policy.h>
#include <diskusage/dirsize.h>
#include <selinux/android.h>
@@ -176,10 +177,6 @@ int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
return 0;
}
-static int lib_dir_matcher(const char* file_name, const int is_dir) {
- return is_dir && !strcmp(file_name, "lib");
-}
-
int delete_user_data(const char *pkgname, userid_t userid)
{
char pkgdir[PKG_PATH_MAX];
@@ -187,8 +184,7 @@ int delete_user_data(const char *pkgname, userid_t userid)
if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid))
return -1;
- /* delete contents, excluding "lib", but not the directory itself */
- return delete_dir_contents(pkgdir, 0, &lib_dir_matcher);
+ return delete_dir_contents(pkgdir, 0, NULL);
}
int make_user_data(const char *pkgname, uid_t uid, userid_t userid, const char* seinfo)
@@ -310,10 +306,27 @@ int delete_cache(const char *pkgname, userid_t userid)
if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, userid))
return -1;
- /* delete contents, not the directory, no exceptions */
+ /* delete contents, not the directory, no exceptions */
return delete_dir_contents(cachedir, 0, NULL);
}
+int delete_code_cache(const char *pkgname, userid_t userid)
+{
+ char codecachedir[PKG_PATH_MAX];
+ struct stat s;
+
+ if (create_pkg_path(codecachedir, pkgname, CODE_CACHE_DIR_POSTFIX, userid))
+ return -1;
+
+ /* it's okay if code cache is missing */
+ if (lstat(codecachedir, &s) == -1 && errno == ENOENT) {
+ return 0;
+ }
+
+ /* delete contents, not the directory, no exceptions */
+ return delete_dir_contents(codecachedir, 0, NULL);
+}
+
/* Try to ensure free_size bytes of storage are available.
* Returns 0 on success.
* This is rather simple-minded because doing a full LRU would
@@ -409,8 +422,14 @@ int move_dex(const char *src, const char *dst, const char *instruction_set)
char src_dex[PKG_PATH_MAX];
char dst_dex[PKG_PATH_MAX];
- if (validate_apk_path(src)) return -1;
- if (validate_apk_path(dst)) return -1;
+ if (validate_apk_path(src)) {
+ ALOGE("invalid apk path '%s' (bad prefix)\n", src);
+ return -1;
+ }
+ if (validate_apk_path(dst)) {
+ ALOGE("invalid apk path '%s' (bad prefix)\n", dst);
+ return -1;
+ }
if (create_cache_path(src_dex, src, instruction_set)) return -1;
if (create_cache_path(dst_dex, dst, instruction_set)) return -1;
@@ -428,12 +447,18 @@ int rm_dex(const char *path, const char *instruction_set)
{
char dex_path[PKG_PATH_MAX];
- if (validate_apk_path(path)) return -1;
+ if (validate_apk_path(path) && validate_system_app_path(path)) {
+ ALOGE("invalid apk path '%s' (bad prefix)\n", path);
+ return -1;
+ }
+
if (create_cache_path(dex_path, path, instruction_set)) return -1;
ALOGV("unlink %s\n", dex_path);
if (unlink(dex_path) < 0) {
- ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
+ if (errno != ENOENT) {
+ ALOGE("Couldn't unlink %s: %s\n", dex_path, strerror(errno));
+ }
return -1;
} else {
return 0;
@@ -559,7 +584,6 @@ done:
return 0;
}
-
int create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *instruction_set)
{
char *tmp;
@@ -622,9 +646,58 @@ static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
}
-static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
+static void run_patchoat(int input_fd, int oat_fd, const char* input_file_name,
const char* output_file_name, const char *pkgname, const char *instruction_set)
{
+ static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
+ static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
+
+ static const char* PATCHOAT_BIN = "/system/bin/patchoat";
+ if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
+ ALOGE("Instruction set %s longer than max length of %d",
+ instruction_set, MAX_INSTRUCTION_SET_LEN);
+ return;
+ }
+
+ /* input_file_name/input_fd should be the .odex/.oat file that is precompiled. I think*/
+ char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
+ char output_oat_fd_arg[strlen("--output-oat-fd=") + MAX_INT_LEN];
+ char input_oat_fd_arg[strlen("--input-oat-fd=") + MAX_INT_LEN];
+ const char* patched_image_location_arg = "--patched-image-location=/system/framework/boot.art";
+ // The caller has already gotten all the locks we need.
+ const char* no_lock_arg = "--no-lock-output";
+ sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
+ sprintf(output_oat_fd_arg, "--output-oat-fd=%d", oat_fd);
+ sprintf(input_oat_fd_arg, "--input-oat-fd=%d", input_fd);
+ ALOGE("Running %s isa=%s in-fd=%d (%s) out-fd=%d (%s)\n",
+ PATCHOAT_BIN, instruction_set, input_fd, input_file_name, oat_fd, output_file_name);
+
+ /* patchoat, patched-image-location, no-lock, isa, input-fd, output-fd */
+ char* argv[7];
+ argv[0] = (char*) PATCHOAT_BIN;
+ argv[1] = (char*) patched_image_location_arg;
+ argv[2] = (char*) no_lock_arg;
+ argv[3] = instruction_set_arg;
+ argv[4] = output_oat_fd_arg;
+ argv[5] = input_oat_fd_arg;
+ argv[6] = NULL;
+
+ execv(PATCHOAT_BIN, (char* const *)argv);
+ ALOGE("execv(%s) failed: %s\n", PATCHOAT_BIN, strerror(errno));
+}
+
+static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
+ const char* output_file_name, const char *pkgname, const char *instruction_set,
+ bool vm_safe_mode)
+{
+ static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
+
+ if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
+ ALOGE("Instruction set %s longer than max length of %d",
+ instruction_set, MAX_INSTRUCTION_SET_LEN);
+ return;
+ }
+
char prop_buf[PROPERTY_VALUE_MAX];
bool profiler = (property_get("dalvik.vm.profiler", prop_buf, "0") > 0) && (prop_buf[0] == '1');
@@ -634,38 +707,51 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
char dex2oat_Xmx_flag[PROPERTY_VALUE_MAX];
bool have_dex2oat_Xmx_flag = property_get("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, NULL) > 0;
+ char dex2oat_compiler_filter_flag[PROPERTY_VALUE_MAX];
+ bool have_dex2oat_compiler_filter_flag = property_get("dalvik.vm.dex2oat-filter",
+ dex2oat_compiler_filter_flag, NULL) > 0;
+
+ char dex2oat_isa_features_key[PROPERTY_KEY_MAX];
+ sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);
+ char dex2oat_isa_features[PROPERTY_VALUE_MAX];
+ bool have_dex2oat_isa_features = property_get(dex2oat_isa_features_key,
+ dex2oat_isa_features, NULL) > 0;
+
char dex2oat_flags[PROPERTY_VALUE_MAX];
bool have_dex2oat_flags = property_get("dalvik.vm.dex2oat-flags", dex2oat_flags, NULL) > 0;
ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags);
+ // If we booting without the real /data, don't spend time compiling.
+ char vold_decrypt[PROPERTY_VALUE_MAX];
+ bool have_vold_decrypt = property_get("vold.decrypt", vold_decrypt, "") > 0;
+ bool skip_compilation = (have_vold_decrypt &&
+ (strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 ||
+ (strcmp(vold_decrypt, "1") == 0)));
+
static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
static const char* RUNTIME_ARG = "--runtime-arg";
static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
- static const unsigned int MAX_INSTRUCTION_SET_LEN = 32;
-
- if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
- ALOGE("Instruction set %s longer than max length of %d",
- instruction_set, MAX_INSTRUCTION_SET_LEN);
- return;
- }
char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN];
char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX];
char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN];
char oat_location_arg[strlen("--oat-location=") + PKG_PATH_MAX];
char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
+ 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];
sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd);
sprintf(zip_location_arg, "--zip-location=%s", input_file_name);
sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
+ sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features);
bool have_profile_file = false;
bool have_top_k_profile_threshold = false;
@@ -691,14 +777,25 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
if (have_dex2oat_Xmx_flag) {
sprintf(dex2oat_Xmx_arg, "-Xmx%s", dex2oat_Xmx_flag);
}
+ if (skip_compilation) {
+ strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=verify-none");
+ have_dex2oat_compiler_filter_flag = true;
+ } else if (vm_safe_mode) {
+ strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=interpret-only");
+ have_dex2oat_compiler_filter_flag = true;
+ } else if (have_dex2oat_compiler_filter_flag) {
+ sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", dex2oat_compiler_filter_flag);
+ }
ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name);
char* argv[7 // program name, mandatory arguments and the final NULL
+ + (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)
+ (have_dex2oat_flags ? 1 : 0)];
int i = 0;
argv[i++] = (char*)DEX2OAT_BIN;
@@ -707,6 +804,9 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
argv[i++] = oat_fd_arg;
argv[i++] = oat_location_arg;
argv[i++] = instruction_set_arg;
+ if (have_dex2oat_isa_features) {
+ argv[i++] = instruction_set_features_arg;
+ }
if (have_profile_file) {
argv[i++] = profile_file_arg;
}
@@ -721,6 +821,9 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
argv[i++] = (char*)RUNTIME_ARG;
argv[i++] = dex2oat_Xmx_arg;
}
+ if (have_dex2oat_compiler_filter_flag) {
+ argv[i++] = dex2oat_compiler_filter_arg;
+ }
if (have_dex2oat_flags) {
argv[i++] = dex2oat_flags;
}
@@ -757,15 +860,18 @@ static int wait_child(pid_t pid)
}
}
-int dexopt(const char *apk_path, uid_t uid, int is_public,
- const char *pkgname, const char *instruction_set)
+int dexopt(const char *apk_path, uid_t uid, bool is_public,
+ const char *pkgname, const char *instruction_set,
+ bool vm_safe_mode, bool is_patchoat)
{
struct utimbuf ut;
- struct stat apk_stat, dex_stat;
+ struct stat input_stat, dex_stat;
char out_path[PKG_PATH_MAX];
char persist_sys_dalvik_vm_lib[PROPERTY_VALUE_MAX];
char *end;
- int res, zip_fd=-1, out_fd=-1;
+ const char *input_file;
+ char in_odex_path[PKG_PATH_MAX];
+ int res, input_fd=-1, out_fd=-1;
if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
return -1;
@@ -774,12 +880,20 @@ int dexopt(const char *apk_path, uid_t uid, int is_public,
/* The command to run depend on the value of persist.sys.dalvik.vm.lib */
property_get("persist.sys.dalvik.vm.lib.2", persist_sys_dalvik_vm_lib, "libart.so");
+ if (is_patchoat && strncmp(persist_sys_dalvik_vm_lib, "libart", 6) != 0) {
+ /* We may only patch if we are libart */
+ ALOGE("Patching is only supported in libart\n");
+ return -1;
+ }
+
/* Before anything else: is there a .odex file? If so, we have
* precompiled the apk and there is nothing to do here.
+ *
+ * We skip this if we are doing a patchoat.
*/
strcpy(out_path, apk_path);
end = strrchr(out_path, '.');
- if (end != NULL) {
+ if (end != NULL && !is_patchoat) {
strcpy(end, ".odex");
if (stat(out_path, &dex_stat) == 0) {
return 0;
@@ -790,12 +904,33 @@ int dexopt(const char *apk_path, uid_t uid, int is_public,
return -1;
}
- memset(&apk_stat, 0, sizeof(apk_stat));
- stat(apk_path, &apk_stat);
+ if (is_patchoat) {
+ /* /system/framework/whatever.jar -> /system/framework/<isa>/whatever.odex */
+ strcpy(in_odex_path, apk_path);
+ end = strrchr(in_odex_path, '/');
+ if (end == NULL) {
+ ALOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
+ return -1;
+ }
+ const char *apk_end = apk_path + (end - in_odex_path); // strrchr(apk_path, '/');
+ strcpy(end + 1, instruction_set); // in_odex_path now is /system/framework/<isa>\0
+ strcat(in_odex_path, apk_end);
+ end = strrchr(in_odex_path, '.');
+ if (end == NULL) {
+ return -1;
+ }
+ strcpy(end + 1, "odex");
+ input_file = in_odex_path;
+ } else {
+ input_file = apk_path;
+ }
+
+ memset(&input_stat, 0, sizeof(input_stat));
+ stat(input_file, &input_stat);
- zip_fd = open(apk_path, O_RDONLY, 0);
- if (zip_fd < 0) {
- ALOGE("installd cannot open '%s' for input during dexopt\n", apk_path);
+ input_fd = open(input_file, O_RDONLY, 0);
+ if (input_fd < 0) {
+ ALOGE("installd cannot open '%s' for input during dexopt\n", input_file);
return -1;
}
@@ -822,7 +957,7 @@ int dexopt(const char *apk_path, uid_t uid, int is_public,
}
- ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path);
+ ALOGV("DexInv: --- BEGIN '%s' ---\n", input_file);
pid_t pid;
pid = fork();
@@ -846,15 +981,24 @@ int dexopt(const char *apk_path, uid_t uid, int is_public,
ALOGE("capset failed: %s\n", strerror(errno));
exit(66);
}
+ if (set_sched_policy(0, SP_BACKGROUND) < 0) {
+ ALOGE("set_sched_policy failed: %s\n", strerror(errno));
+ exit(70);
+ }
if (flock(out_fd, LOCK_EX | LOCK_NB) != 0) {
ALOGE("flock(%s) failed: %s\n", out_path, strerror(errno));
exit(67);
}
if (strncmp(persist_sys_dalvik_vm_lib, "libdvm", 6) == 0) {
- run_dexopt(zip_fd, out_fd, apk_path, out_path);
+ run_dexopt(input_fd, out_fd, input_file, out_path);
} else if (strncmp(persist_sys_dalvik_vm_lib, "libart", 6) == 0) {
- run_dex2oat(zip_fd, out_fd, apk_path, out_path, pkgname, instruction_set);
+ if (is_patchoat) {
+ run_patchoat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set);
+ } else {
+ run_dex2oat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set,
+ vm_safe_mode);
+ }
} else {
exit(69); /* Unexpected persist.sys.dalvik.vm.lib value */
}
@@ -862,19 +1006,19 @@ int dexopt(const char *apk_path, uid_t uid, int is_public,
} else {
res = wait_child(pid);
if (res == 0) {
- ALOGV("DexInv: --- END '%s' (success) ---\n", apk_path);
+ ALOGV("DexInv: --- END '%s' (success) ---\n", input_file);
} else {
- ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", apk_path, res);
+ ALOGE("DexInv: --- END '%s' --- status=0x%04x, process failed\n", input_file, res);
goto fail;
}
}
- ut.actime = apk_stat.st_atime;
- ut.modtime = apk_stat.st_mtime;
+ ut.actime = input_stat.st_atime;
+ ut.modtime = input_stat.st_mtime;
utime(out_path, &ut);
close(out_fd);
- close(zip_fd);
+ close(input_fd);
return 0;
fail:
@@ -882,8 +1026,8 @@ fail:
close(out_fd);
unlink(out_path);
}
- if (zip_fd >= 0) {
- close(zip_fd);
+ if (input_fd >= 0) {
+ close(input_fd);
}
return -1;
}
@@ -1411,50 +1555,3 @@ int restorecon_data(const char* pkgName, const char* seinfo, uid_t uid)
return ret;
}
-static int prune_dex_exclusion_predicate(const char *file_name, const int is_dir)
-{
- // Exclude all directories. The top level command will be
- // given a list of ISA specific directories that are assumed
- // to be flat.
- if (is_dir) {
- return 1;
- }
-
-
- // Don't exclude regular files that start with the list
- // of prefixes.
- static const char data_app_prefix[] = "data@app@";
- static const char data_priv_app_prefix[] = "data@priv-app@";
- if (!strncmp(file_name, data_app_prefix, sizeof(data_app_prefix) - 1) ||
- !strncmp(file_name, data_priv_app_prefix, sizeof(data_priv_app_prefix) - 1)) {
- return 0;
- }
-
- // Exclude all regular files that don't start with the prefix "data@app@" or
- // "data@priv-app@".
- return 1;
-}
-
-int prune_dex_cache(const char* subdir) {
- // "." is handled as a special case, and refers to
- // DALVIK_CACHE_PREFIX (usually /data/dalvik-cache).
- const bool is_dalvik_cache_root = !strcmp(subdir, ".");
-
- // Don't allow the path to contain "." or ".." except for the
- // special case above. This is much stricter than we need to be,
- // but there's no good reason to support them.
- if (strchr(subdir, '.' ) != NULL && !is_dalvik_cache_root) {
- return -1;
- }
-
- if (!is_dalvik_cache_root) {
- char full_path[PKG_PATH_MAX];
- snprintf(full_path, sizeof(full_path), "%s%s", DALVIK_CACHE_PREFIX, subdir);
- return delete_dir_contents(full_path, 0, &prune_dex_exclusion_predicate);
- }
-
-
- // When subdir == ".", clean the contents of the top level
- // dalvik-cache directory.
- return delete_dir_contents(DALVIK_CACHE_PREFIX, 0, &prune_dex_exclusion_predicate);
-}
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index e072d0d..3078f20 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -15,7 +15,7 @@
*/
#include <sys/capability.h>
-#include <linux/prctl.h>
+#include <sys/prctl.h>
#include <selinux/android.h>
#include <selinux/avc.h>
@@ -38,8 +38,8 @@ static int do_install(char **arg, char reply[REPLY_MAX])
static int do_dexopt(char **arg, char reply[REPLY_MAX])
{
- /* apk_path, uid, is_public, pkgname, instruction_set */
- return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3], arg[4]);
+ /* apk_path, uid, is_public, pkgname, instruction_set, vm_safe_mode, should_relocate */
+ return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3], arg[4], atoi(arg[5]), 0);
}
static int do_move_dex(char **arg, char reply[REPLY_MAX])
@@ -77,6 +77,11 @@ static int do_rm_cache(char **arg, char reply[REPLY_MAX])
return delete_cache(arg[0], atoi(arg[1])); /* pkgname, userid */
}
+static int do_rm_code_cache(char **arg, char reply[REPLY_MAX])
+{
+ return delete_code_cache(arg[0], atoi(arg[1])); /* pkgname, userid */
+}
+
static int do_get_size(char **arg, char reply[REPLY_MAX])
{
int64_t codesize = 0;
@@ -140,10 +145,9 @@ static int do_restorecon_data(char **arg, char reply[REPLY_MAX] __attribute__((u
/* pkgName, seinfo, uid*/
}
-static int do_prune_dex_cache(char **arg __attribute__((unused)),
- char reply[REPLY_MAX] __attribute__((unused)))
-{
- return prune_dex_cache(arg[0] /* subdirectory name */);
+static int do_patchoat(char **arg, char reply[REPLY_MAX]) {
+ /* apk_path, uid, is_public, pkgname, instruction_set, vm_safe_mode, should_relocate */
+ return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3], arg[4], 0, 1);
}
struct cmdinfo {
@@ -155,7 +159,7 @@ struct cmdinfo {
struct cmdinfo cmds[] = {
{ "ping", 0, do_ping },
{ "install", 4, do_install },
- { "dexopt", 5, do_dexopt },
+ { "dexopt", 6, do_dexopt },
{ "movedex", 3, do_move_dex },
{ "rmdex", 2, do_rm_dex },
{ "remove", 2, do_remove },
@@ -163,6 +167,7 @@ struct cmdinfo cmds[] = {
{ "fixuid", 3, do_fixuid },
{ "freecache", 1, do_free_cache },
{ "rmcache", 2, do_rm_cache },
+ { "rmcodecache", 2, do_rm_code_cache },
{ "getsize", 7, do_get_size },
{ "rmuserdata", 2, do_rm_user_data },
{ "movefiles", 0, do_movefiles },
@@ -172,7 +177,7 @@ struct cmdinfo cmds[] = {
{ "rmuser", 1, do_rm_user },
{ "idmap", 3, do_idmap },
{ "restorecondata", 3, do_restorecon_data },
- { "prunedexcache", 1, do_prune_dex_cache },
+ { "patchoat", 5, do_patchoat },
};
static int readx(int s, void *_buf, int count)
@@ -323,7 +328,7 @@ int initialize_globals() {
}
// Take note of the system and vendor directories.
- android_system_dirs.count = 2;
+ android_system_dirs.count = 4;
android_system_dirs.dirs = calloc(android_system_dirs.count, sizeof(dir_rec_t));
if (android_system_dirs.dirs == NULL) {
@@ -331,22 +336,24 @@ int initialize_globals() {
return -1;
}
- // system
- if (get_path_from_env(&android_system_dirs.dirs[0], "ANDROID_ROOT") < 0) {
- free_globals();
+ dir_rec_t android_root_dir;
+ if (get_path_from_env(&android_root_dir, "ANDROID_ROOT") < 0) {
+ ALOGE("Missing ANDROID_ROOT; aborting\n");
return -1;
}
- // append "app/" to dirs[0]
- char *system_app_path = build_string2(android_system_dirs.dirs[0].path, APP_SUBDIR);
- android_system_dirs.dirs[0].path = system_app_path;
- android_system_dirs.dirs[0].len = strlen(system_app_path);
+ android_system_dirs.dirs[0].path = build_string2(android_root_dir.path, APP_SUBDIR);
+ android_system_dirs.dirs[0].len = strlen(android_system_dirs.dirs[0].path);
- // vendor
- // TODO replace this with an environment variable (doesn't exist yet)
- android_system_dirs.dirs[1].path = "/vendor/app/";
+ android_system_dirs.dirs[1].path = build_string2(android_root_dir.path, PRIV_APP_SUBDIR);
android_system_dirs.dirs[1].len = strlen(android_system_dirs.dirs[1].path);
+ android_system_dirs.dirs[2].path = "/vendor/app/";
+ android_system_dirs.dirs[2].len = strlen(android_system_dirs.dirs[2].path);
+
+ android_system_dirs.dirs[3].path = "/oem/app/";
+ android_system_dirs.dirs[3].len = strlen(android_system_dirs.dirs[3].path);
+
return 0;
}
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 258647a..a5cad45 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -59,8 +59,10 @@
#define PKG_LIB_POSTFIX "/lib"
#define CACHE_DIR_POSTFIX "/cache"
+#define CODE_CACHE_DIR_POSTFIX "/code_cache"
#define APP_SUBDIR "app/" // sub-directory under ANDROID_DATA
+#define PRIV_APP_SUBDIR "priv-app/" // sub-directory under ANDROID_DATA
#define APP_LIB_SUBDIR "app-lib/" // sub-directory under ANDROID_DATA
@@ -207,6 +209,7 @@ int make_user_data(const char *pkgname, uid_t uid, userid_t userid, const char*
int make_user_config(userid_t userid);
int delete_user(userid_t userid);
int delete_cache(const char *pkgname, userid_t userid);
+int delete_code_cache(const char *pkgname, userid_t userid);
int move_dex(const char *src, const char *dst, const char *instruction_set);
int rm_dex(const char *path, const char *instruction_set);
int protect(char *pkgname, gid_t gid);
@@ -214,10 +217,9 @@ int get_size(const char *pkgname, userid_t userid, const char *apkpath, const ch
const char *fwdlock_apkpath, const char *asecpath, const char *instruction_set,
int64_t *codesize, int64_t *datasize, int64_t *cachesize, int64_t *asecsize);
int free_cache(int64_t free_size);
-int dexopt(const char *apk_path, uid_t uid, int is_public, const char *pkgName,
- const char *instruction_set);
+int dexopt(const char *apk_path, uid_t uid, bool is_public, const char *pkgName,
+ const char *instruction_set, bool vm_safe_mode, bool should_relocate);
int movefiles();
int linklib(const char* target, const char* source, int userId);
int idmap(const char *target_path, const char *overlay_path, uid_t uid);
int restorecon_data();
-int prune_dex_cache(const char* subdir);
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 0b182af..94e4792 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -101,6 +101,11 @@ TEST_F(UtilsTest, IsValidApkPath_Internal) {
EXPECT_EQ(0, validate_apk_path(internal1))
<< internal1 << " should be allowed as a valid path";
+ // b/16888084
+ const char *path2 = TEST_APP_DIR "example.com/example.apk";
+ EXPECT_EQ(0, validate_apk_path(path2))
+ << path2 << " should be allowed as a valid path";
+
const char *badint1 = TEST_APP_DIR "../example.apk";
EXPECT_EQ(-1, validate_apk_path(badint1))
<< badint1 << " should be rejected as a invalid path";
@@ -109,9 +114,18 @@ TEST_F(UtilsTest, IsValidApkPath_Internal) {
EXPECT_EQ(-1, validate_apk_path(badint2))
<< badint2 << " should be rejected as a invalid path";
- const char *badint3 = TEST_APP_DIR "example.com/pkg.apk";
- EXPECT_EQ(-1, validate_apk_path(badint3))
- << badint3 << " should be rejected as a invalid path";
+ // Only one subdir should be allowed.
+ const char *bad_path3 = TEST_APP_DIR "example.com/subdir/pkg.apk";
+ EXPECT_EQ(-1, validate_apk_path(bad_path3))
+ << bad_path3 << " should be rejected as a invalid path";
+
+ const char *bad_path4 = TEST_APP_DIR "example.com/subdir/../pkg.apk";
+ EXPECT_EQ(-1, validate_apk_path(bad_path4))
+ << bad_path4 << " should be rejected as a invalid path";
+
+ const char *bad_path5 = TEST_APP_DIR "example.com1/../example.com2/pkg.apk";
+ EXPECT_EQ(-1, validate_apk_path(bad_path5))
+ << bad_path5 << " should be rejected as a invalid path";
}
TEST_F(UtilsTest, IsValidApkPath_Private) {
@@ -120,6 +134,11 @@ TEST_F(UtilsTest, IsValidApkPath_Private) {
EXPECT_EQ(0, validate_apk_path(private1))
<< private1 << " should be allowed as a valid path";
+ // b/16888084
+ const char *path2 = TEST_APP_DIR "example.com/example.apk";
+ EXPECT_EQ(0, validate_apk_path(path2))
+ << path2 << " should be allowed as a valid path";
+
const char *badpriv1 = TEST_APP_PRIVATE_DIR "../example.apk";
EXPECT_EQ(-1, validate_apk_path(badpriv1))
<< badpriv1 << " should be rejected as a invalid path";
@@ -128,9 +147,18 @@ TEST_F(UtilsTest, IsValidApkPath_Private) {
EXPECT_EQ(-1, validate_apk_path(badpriv2))
<< badpriv2 << " should be rejected as a invalid path";
- const char *badpriv3 = TEST_APP_PRIVATE_DIR "example.com/pkg.apk";
- EXPECT_EQ(-1, validate_apk_path(badpriv3))
- << badpriv3 << " should be rejected as a invalid path";
+ // Only one subdir should be allowed.
+ const char *bad_path3 = TEST_APP_PRIVATE_DIR "example.com/subdir/pkg.apk";
+ EXPECT_EQ(-1, validate_apk_path(bad_path3))
+ << bad_path3 << " should be rejected as a invalid path";
+
+ const char *bad_path4 = TEST_APP_PRIVATE_DIR "example.com/subdir/../pkg.apk";
+ EXPECT_EQ(-1, validate_apk_path(bad_path4))
+ << bad_path4 << " should be rejected as a invalid path";
+
+ const char *bad_path5 = TEST_APP_PRIVATE_DIR "example.com1/../example.com2/pkg.apk";
+ EXPECT_EQ(-1, validate_apk_path(bad_path5))
+ << bad_path5 << " should be rejected as a invalid path";
}
@@ -218,6 +246,24 @@ TEST_F(UtilsTest, CheckSystemApp_BadPathEscapeFail) {
<< badapp3 << " should be rejected not a system path";
}
+TEST_F(UtilsTest, CheckSystemApp_Subdir) {
+ const char *sysapp = TEST_SYSTEM_DIR1 "com.example/com.example.apk";
+ EXPECT_EQ(0, validate_system_app_path(sysapp))
+ << sysapp << " should be allowed as a system path";
+
+ const char *badapp = TEST_SYSTEM_DIR1 "com.example/subdir/com.example.apk";
+ EXPECT_EQ(-1, validate_system_app_path(badapp))
+ << badapp << " should be rejected not a system path";
+
+ const char *badapp1 = TEST_SYSTEM_DIR1 "com.example/subdir/../com.example.apk";
+ EXPECT_EQ(-1, validate_system_app_path(badapp1))
+ << badapp1 << " should be rejected not a system path";
+
+ const char *badapp2 = TEST_SYSTEM_DIR1 "com.example1/../com.example2/com.example.apk";
+ EXPECT_EQ(-1, validate_system_app_path(badapp2))
+ << badapp2 << " should be rejected not a system path";
+}
+
TEST_F(UtilsTest, GetPathFromString_NullPathFail) {
dir_rec_t test1;
EXPECT_EQ(-1, get_path_from_string(&test1, (const char *) NULL))
diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c
index 35172de..60d20de 100644
--- a/cmds/installd/utils.c
+++ b/cmds/installd/utils.c
@@ -808,6 +808,33 @@ void finish_cache_collection(cache_t* cache)
}
/**
+ * Validate that the path is valid in the context of the provided directory.
+ * The path is allowed to have at most one subdirectory and no indirections
+ * to top level directories (i.e. have "..").
+ */
+static int validate_path(const dir_rec_t* dir, const char* path) {
+ size_t dir_len = dir->len;
+ const char* subdir = strchr(path + dir_len, '/');
+
+ // Only allow the path to have at most one subdirectory.
+ if (subdir != NULL) {
+ ++subdir;
+ if (strchr(subdir, '/') != NULL) {
+ ALOGE("invalid apk path '%s' (subdir?)\n", path);
+ return -1;
+ }
+ }
+
+ // Directories can't have a period directly after the directory markers to prevent "..".
+ if ((path[dir_len] == '.') || ((subdir != NULL) && (*subdir == '.'))) {
+ ALOGE("invalid apk path '%s' (trickery)\n", path);
+ return -1;
+ }
+
+ return 0;
+}
+
+/**
* Checks whether a path points to a system app (.apk file). Returns 0
* if it is a system app or -1 if it is not.
*/
@@ -817,11 +844,7 @@ int validate_system_app_path(const char* path) {
for (i = 0; i < android_system_dirs.count; i++) {
const size_t dir_len = android_system_dirs.dirs[i].len;
if (!strncmp(path, android_system_dirs.dirs[i].path, dir_len)) {
- if (path[dir_len] == '.' || strchr(path + dir_len, '/') != NULL) {
- ALOGE("invalid system apk path '%s' (trickery)\n", path);
- return -1;
- }
- return 0;
+ return validate_path(android_system_dirs.dirs + i, path);
}
}
@@ -914,54 +937,25 @@ int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) {
}
/**
- * Check whether path points to a valid path for an APK file. An ASEC
- * directory is allowed to have one level of subdirectory names. Returns -1
- * when an invalid path is encountered and 0 when a valid path is encountered.
+ * Check whether path points to a valid path for an APK file. Only one level of
+ * subdirectory names is allowed. Returns -1 when an invalid path is encountered
+ * and 0 when a valid path is encountered.
*/
int validate_apk_path(const char *path)
{
- int allowsubdir = 0;
- char *subdir = NULL;
- size_t dir_len;
- size_t path_len;
+ const dir_rec_t* dir = NULL;
if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
- dir_len = android_app_dir.len;
+ dir = &android_app_dir;
} else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) {
- dir_len = android_app_private_dir.len;
+ dir = &android_app_private_dir;
} else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) {
- dir_len = android_asec_dir.len;
- allowsubdir = 1;
+ dir = &android_asec_dir;
} else {
- ALOGE("invalid apk path '%s' (bad prefix)\n", path);
return -1;
}
- path_len = strlen(path);
-
- /*
- * Only allow the path to have a subdirectory if it's been marked as being allowed.
- */
- if ((subdir = strchr(path + dir_len, '/')) != NULL) {
- ++subdir;
- if (!allowsubdir
- || (path_len > (size_t) (subdir - path) && (strchr(subdir, '/') != NULL))) {
- ALOGE("invalid apk path '%s' (subdir?)\n", path);
- return -1;
- }
- }
-
- /*
- * Directories can't have a period directly after the directory markers
- * to prevent ".."
- */
- if (path[dir_len] == '.'
- || (subdir != NULL && ((*subdir == '.') || (strchr(subdir, '/') != NULL)))) {
- ALOGE("invalid apk path '%s' (trickery)\n", path);
- return -1;
- }
-
- return 0;
+ return validate_path(dir, path);
}
int append_and_increment(char** dst, const char* src, size_t* dst_size) {
diff --git a/cmds/screenshot/Android.mk b/cmds/screenshot/Android.mk
deleted file mode 100644
index 1ee7807..0000000
--- a/cmds/screenshot/Android.mk
+++ /dev/null
@@ -1,12 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := screenshot.c
-
-LOCAL_MODULE := screenshot
-
-LOCAL_SHARED_LIBRARIES := libcutils libz liblog
-LOCAL_STATIC_LIBRARIES := libpng
-LOCAL_C_INCLUDES += external/zlib external/libpng
-
-include $(BUILD_EXECUTABLE)
diff --git a/cmds/screenshot/screenshot.c b/cmds/screenshot/screenshot.c
deleted file mode 100644
index be1ecd4..0000000
--- a/cmds/screenshot/screenshot.c
+++ /dev/null
@@ -1,171 +0,0 @@
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include <linux/fb.h>
-
-#include <zlib.h>
-#include <png.h>
-
-#include "private/android_filesystem_config.h"
-
-#define LOG_TAG "screenshot"
-#include <utils/Log.h>
-
-void take_screenshot(FILE *fb_in, FILE *fb_out) {
- int fb;
- char imgbuf[0x10000];
- struct fb_var_screeninfo vinfo;
- png_structp png;
- png_infop info;
- unsigned int r,c,rowlen;
- unsigned int bytespp,offset;
-
- fb = fileno(fb_in);
- if(fb < 0) {
- ALOGE("failed to open framebuffer\n");
- return;
- }
- fb_in = fdopen(fb, "r");
-
- if(ioctl(fb, FBIOGET_VSCREENINFO, &vinfo) < 0) {
- ALOGE("failed to get framebuffer info\n");
- return;
- }
- fcntl(fb, F_SETFD, FD_CLOEXEC);
-
- png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- if (png == NULL) {
- ALOGE("failed png_create_write_struct\n");
- fclose(fb_in);
- return;
- }
-
- png_init_io(png, fb_out);
- info = png_create_info_struct(png);
- if (info == NULL) {
- ALOGE("failed png_create_info_struct\n");
- png_destroy_write_struct(&png, NULL);
- fclose(fb_in);
- return;
- }
- if (setjmp(png_jmpbuf(png))) {
- ALOGE("failed png setjmp\n");
- png_destroy_write_struct(&png, NULL);
- fclose(fb_in);
- return;
- }
-
- bytespp = vinfo.bits_per_pixel / 8;
- png_set_IHDR(png, info,
- vinfo.xres, vinfo.yres, vinfo.bits_per_pixel / 4,
- PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
- PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE);
- png_write_info(png, info);
-
- rowlen=vinfo.xres * bytespp;
- if (rowlen > sizeof(imgbuf)) {
- ALOGE("crazy rowlen: %d\n", rowlen);
- png_destroy_write_struct(&png, NULL);
- fclose(fb_in);
- return;
- }
-
- offset = vinfo.xoffset * bytespp + vinfo.xres * vinfo.yoffset * bytespp;
- fseek(fb_in, offset, SEEK_SET);
-
- for(r=0; r<vinfo.yres; r++) {
- int len = fread(imgbuf, 1, rowlen, fb_in);
- if (len <= 0) break;
- png_write_row(png, (png_bytep)imgbuf);
- }
-
- png_write_end(png, info);
- fclose(fb_in);
- png_destroy_write_struct(&png, NULL);
-}
-
-void fork_sound(const char* path) {
- pid_t pid = fork();
- if (pid == 0) {
- execl("/system/bin/stagefright", "stagefright", "-o", "-a", path, NULL);
- }
-}
-
-void usage() {
- fprintf(stderr,
- "usage: screenshot [-s soundfile] filename.png\n"
- " -s: play a sound effect to signal success\n"
- " -i: autoincrement to avoid overwriting filename.png\n"
- );
-}
-
-int main(int argc, char**argv) {
- FILE *png = NULL;
- FILE *fb_in = NULL;
- char outfile[PATH_MAX] = "";
-
- char * soundfile = NULL;
- int do_increment = 0;
-
- int c;
- while ((c = getopt(argc, argv, "s:i")) != -1) {
- switch (c) {
- case 's': soundfile = optarg; break;
- case 'i': do_increment = 1; break;
- case '?':
- case 'h':
- usage(); exit(1);
- }
- }
- argc -= optind;
- argv += optind;
-
- if (argc < 1) {
- usage(); exit(1);
- }
-
- strlcpy(outfile, argv[0], PATH_MAX);
- if (do_increment) {
- struct stat st;
- char base[PATH_MAX] = "";
- int i = 0;
- while (stat(outfile, &st) == 0) {
- if (!base[0]) {
- char *p = strrchr(outfile, '.');
- if (p) *p = '\0';
- strcpy(base, outfile);
- }
- snprintf(outfile, PATH_MAX, "%s-%d.png", base, ++i);
- }
- }
-
- fb_in = fopen("/dev/graphics/fb0", "r");
- if (!fb_in) {
- fprintf(stderr, "error: could not read framebuffer\n");
- exit(1);
- }
-
- /* switch to non-root user and group */
- gid_t groups[] = { AID_LOG, AID_SDCARD_RW };
- setgroups(sizeof(groups)/sizeof(groups[0]), groups);
- setuid(AID_SHELL);
-
- png = fopen(outfile, "w");
- if (!png) {
- fprintf(stderr, "error: writing file %s: %s\n",
- outfile, strerror(errno));
- exit(1);
- }
-
- take_screenshot(fb_in, png);
-
- if (soundfile) {
- fork_sound(soundfile);
- }
-
- exit(0);
-}
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index f142093..f37427a 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -9,6 +9,7 @@
#include <private/android_filesystem_config.h>
#include <selinux/android.h>
+#include <selinux/avc.h>
#include "binder.h"
@@ -22,15 +23,20 @@
uint32_t svcmgr_handle;
-const char *str8(const uint16_t *x)
+const char *str8(const uint16_t *x, size_t x_len)
{
static char buf[128];
- unsigned max = 127;
+ size_t max = 127;
char *p = buf;
+ if (x_len < max) {
+ max = x_len;
+ }
+
if (x) {
- while (*x && max--) {
+ while ((max > 0) && (*x != '\0')) {
*p++ = *x++;
+ max--;
}
}
*p++ = 0;
@@ -46,60 +52,77 @@ int str16eq(const uint16_t *a, const char *b)
return 1;
}
+static int selinux_enabled;
+static char *service_manager_context;
static struct selabel_handle* sehandle;
-static bool check_mac_perms(const char *name, pid_t spid)
+static bool check_mac_perms(pid_t spid, const char *tctx, const char *perm, const char *name)
{
- if (is_selinux_enabled() <= 0) {
- return true;
- }
-
- bool allowed = false;
-
- const char *class = "service_manager";
- const char *perm = "add";
-
- char *tctx = NULL;
char *sctx = NULL;
+ const char *class = "service_manager";
+ bool allowed;
- if (!sehandle) {
- ALOGE("SELinux: Failed to find sehandle %s.\n", name);
+ if (getpidcon(spid, &sctx) < 0) {
+ ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid);
return false;
}
- if (getpidcon(spid, &sctx) < 0) {
- ALOGE("SELinux: getpidcon failed to retrieve pid context.\n");
- return false;
+ int result = selinux_check_access(sctx, tctx, class, perm, (void *) name);
+ allowed = (result == 0);
+
+ freecon(sctx);
+ return allowed;
+}
+
+static bool check_mac_perms_from_getcon(pid_t spid, const char *perm)
+{
+ if (selinux_enabled <= 0) {
+ return true;
}
- if (!sctx) {
- ALOGE("SELinux: Failed to find sctx for %s.\n", name);
- return false;
+ return check_mac_perms(spid, service_manager_context, perm, NULL);
+}
+
+static bool check_mac_perms_from_lookup(pid_t spid, const char *perm, const char *name)
+{
+ bool allowed;
+ char *tctx = NULL;
+
+ if (selinux_enabled <= 0) {
+ return true;
}
- if (selabel_lookup(sehandle, &tctx, name, 1) != 0) {
- ALOGE("SELinux: selabel_lookup failed to set tctx for %s.\n", name);
- freecon(sctx);
- return false;
+ if (!sehandle) {
+ ALOGE("SELinux: Failed to find sehandle. Aborting service_manager.\n");
+ abort();
}
- if (!tctx) {
- ALOGE("SELinux: Failed to find tctx for %s.\n", name);
- freecon(sctx);
+ if (selabel_lookup(sehandle, &tctx, name, 0) != 0) {
+ ALOGE("SELinux: No match for %s in service_contexts.\n", name);
return false;
}
- int result = selinux_check_access(sctx, tctx, class, perm, (void *) name);
- allowed = (result == 0);
-
- freecon(sctx);
+ allowed = check_mac_perms(spid, tctx, perm, name);
freecon(tctx);
return allowed;
}
-static int svc_can_register(uid_t uid, const uint16_t *name, pid_t spid)
+static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid)
{
- return check_mac_perms(str8(name), spid) ? 1 : 0;
+ const char *perm = "add";
+ return check_mac_perms_from_lookup(spid, perm, str8(name, name_len)) ? 1 : 0;
+}
+
+static int svc_can_list(pid_t spid)
+{
+ const char *perm = "list";
+ return check_mac_perms_from_getcon(spid, perm) ? 1 : 0;
+}
+
+static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid)
+{
+ const char *perm = "find";
+ return check_mac_perms_from_lookup(spid, perm, str8(name, name_len)) ? 1 : 0;
}
struct svcinfo
@@ -131,7 +154,7 @@ void svcinfo_death(struct binder_state *bs, void *ptr)
{
struct svcinfo *si = (struct svcinfo* ) ptr;
- ALOGI("service '%s' died\n", str8(si->name));
+ ALOGI("service '%s' died\n", str8(si->name, si->len));
if (si->handle) {
binder_release(bs, si->handle);
si->handle = 0;
@@ -144,12 +167,17 @@ uint16_t svcmgr_id[] = {
};
-uint32_t do_find_service(struct binder_state *bs, const uint16_t *s, size_t len, uid_t uid)
+uint32_t do_find_service(struct binder_state *bs, const uint16_t *s, size_t len, uid_t uid, pid_t spid)
{
struct svcinfo *si;
+ if (!svc_can_find(s, len, spid)) {
+ ALOGE("find_service('%s') uid=%d - PERMISSION DENIED\n",
+ str8(s, len), uid);
+ return 0;
+ }
si = find_svc(s, len);
- //ALOGI("check_service('%s') handle = %x\n", str8(s), si ? si->handle : 0);
+ //ALOGI("check_service('%s') handle = %x\n", str8(s, len), si ? si->handle : 0);
if (si && si->handle) {
if (!si->allow_isolated) {
// If this service doesn't allow access from isolated processes,
@@ -172,15 +200,15 @@ int do_add_service(struct binder_state *bs,
{
struct svcinfo *si;
- //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s), handle,
+ //ALOGI("add_service('%s',%x,%s) uid=%d\n", str8(s, len), handle,
// allow_isolated ? "allow_isolated" : "!allow_isolated", uid);
if (!handle || (len == 0) || (len > 127))
return -1;
- if (!svc_can_register(uid, s, spid)) {
+ if (!svc_can_register(s, len, spid)) {
ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
- str8(s), handle, uid);
+ str8(s, len), handle, uid);
return -1;
}
@@ -188,7 +216,7 @@ int do_add_service(struct binder_state *bs,
if (si) {
if (si->handle) {
ALOGE("add_service('%s',%x) uid=%d - ALREADY REGISTERED, OVERRIDE\n",
- str8(s), handle, uid);
+ str8(s, len), handle, uid);
svcinfo_death(bs, si);
}
si->handle = handle;
@@ -196,7 +224,7 @@ int do_add_service(struct binder_state *bs,
si = malloc(sizeof(*si) + (len + 1) * sizeof(uint16_t));
if (!si) {
ALOGE("add_service('%s',%x) uid=%d - OUT OF MEMORY\n",
- str8(s), handle, uid);
+ str8(s, len), handle, uid);
return -1;
}
si->handle = handle;
@@ -242,9 +270,13 @@ int svcmgr_handler(struct binder_state *bs,
// further (since we do no outbound RPCs anyway).
strict_policy = bio_get_uint32(msg);
s = bio_get_string16(msg, &len);
+ if (s == NULL) {
+ return -1;
+ }
+
if ((len != (sizeof(svcmgr_id) / 2)) ||
memcmp(svcmgr_id, s, sizeof(svcmgr_id))) {
- fprintf(stderr,"invalid id %s\n", str8(s));
+ fprintf(stderr,"invalid id %s\n", str8(s, len));
return -1;
}
@@ -260,7 +292,10 @@ int svcmgr_handler(struct binder_state *bs,
case SVC_MGR_GET_SERVICE:
case SVC_MGR_CHECK_SERVICE:
s = bio_get_string16(msg, &len);
- handle = do_find_service(bs, s, len, txn->sender_euid);
+ if (s == NULL) {
+ return -1;
+ }
+ handle = do_find_service(bs, s, len, txn->sender_euid, txn->sender_pid);
if (!handle)
break;
bio_put_ref(reply, handle);
@@ -268,6 +303,9 @@ int svcmgr_handler(struct binder_state *bs,
case SVC_MGR_ADD_SERVICE:
s = bio_get_string16(msg, &len);
+ if (s == NULL) {
+ return -1;
+ }
handle = bio_get_ref(msg);
allow_isolated = bio_get_uint32(msg) ? 1 : 0;
if (do_add_service(bs, s, len, handle, txn->sender_euid,
@@ -278,6 +316,11 @@ int svcmgr_handler(struct binder_state *bs,
case SVC_MGR_LIST_SERVICES: {
uint32_t n = bio_get_uint32(msg);
+ if (!svc_can_list(txn->sender_pid)) {
+ ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
+ txn->sender_euid);
+ return -1;
+ }
si = svclist;
while ((n-- > 0) && si)
si = si->next;
@@ -318,8 +361,21 @@ int main(int argc, char **argv)
return -1;
}
+ selinux_enabled = is_selinux_enabled();
sehandle = selinux_android_service_context_handle();
+ if (selinux_enabled > 0) {
+ if (sehandle == NULL) {
+ ALOGE("SELinux: Failed to acquire sehandle. Aborting.\n");
+ abort();
+ }
+
+ if (getcon(&service_manager_context) != 0) {
+ ALOGE("SELinux: Failed to acquire service_manager context. Aborting.\n");
+ abort();
+ }
+ }
+
union selinux_callback cb;
cb.func_audit = audit_callback;
selinux_set_callback(SELINUX_CB_AUDIT, cb);