summaryrefslogtreecommitdiffstats
path: root/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'cmds')
-rw-r--r--cmds/atrace/atrace.cpp16
-rw-r--r--cmds/bugreport/Android.mk4
-rw-r--r--cmds/bugreport/bugreport.c56
-rw-r--r--cmds/bugreport/bugreport.cpp91
-rw-r--r--cmds/dumpstate/dumpstate.c27
-rw-r--r--cmds/dumpstate/dumpstate.h8
-rw-r--r--cmds/dumpstate/utils.c249
-rw-r--r--cmds/installd/Android.mk18
-rw-r--r--cmds/installd/commands.cpp (renamed from cmds/installd/commands.c)686
-rw-r--r--cmds/installd/installd.cpp (renamed from cmds/installd/installd.c)228
-rw-r--r--cmds/installd/installd.h74
-rw-r--r--cmds/installd/tests/Android.mk6
-rw-r--r--cmds/installd/tests/installd_utils_test.cpp97
-rw-r--r--cmds/installd/utils.cpp (renamed from cmds/installd/utils.c)239
-rw-r--r--cmds/servicemanager/bctest.c1
-rw-r--r--cmds/servicemanager/binder.c5
-rw-r--r--cmds/servicemanager/service_manager.c45
17 files changed, 1045 insertions, 805 deletions
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index a3d210a..515d761 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -23,6 +23,7 @@
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <sys/sendfile.h>
#include <time.h>
#include <zlib.h>
@@ -34,6 +35,7 @@
#include <cutils/properties.h>
#include <utils/String8.h>
+#include <utils/Timers.h>
#include <utils/Trace.h>
using namespace android;
@@ -191,6 +193,9 @@ static const char* k_tracingOnPath =
static const char* k_tracePath =
"/sys/kernel/debug/tracing/trace";
+static const char* k_traceMarkerPath =
+ "/sys/kernel/debug/tracing/trace_marker";
+
// Check whether a file exists.
static bool fileExists(const char* filename) {
return access(filename, F_OK) != -1;
@@ -253,6 +258,14 @@ static bool appendStr(const char* filename, const char* str)
return _writeStr(filename, str, O_APPEND|O_WRONLY);
}
+static void writeClockSyncMarker()
+{
+ char buffer[128];
+ float now_in_seconds = systemTime(CLOCK_MONOTONIC) / 1000000000.0f;
+ snprintf(buffer, 128, "trace_event_clock_sync: parent_ts=%f\n", now_in_seconds);
+ writeStr(k_traceMarkerPath, buffer);
+}
+
// Enable or disable a kernel option by writing a "1" or a "0" into a /sys
// file.
static bool setKernelOptionEnable(const char* filename, bool enable)
@@ -630,6 +643,7 @@ static bool startTrace()
// Disable tracing in the kernel.
static void stopTrace()
{
+ writeClockSyncMarker();
setTracingEnabled(false);
}
@@ -648,7 +662,7 @@ static void dumpTrace()
uint8_t *in, *out;
int result, flush;
- bzero(&zs, sizeof(zs));
+ memset(&zs, 0, sizeof(zs));
result = deflateInit(&zs, Z_DEFAULT_COMPRESSION);
if (result != Z_OK) {
fprintf(stderr, "error initializing zlib: %d\n", result);
diff --git a/cmds/bugreport/Android.mk b/cmds/bugreport/Android.mk
index f476f5e..ced5d30 100644
--- a/cmds/bugreport/Android.mk
+++ b/cmds/bugreport/Android.mk
@@ -1,10 +1,12 @@
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
-LOCAL_SRC_FILES:= bugreport.c
+LOCAL_SRC_FILES:= bugreport.cpp
LOCAL_MODULE:= bugreport
+LOCAL_CFLAGS := -Wall
+
LOCAL_SHARED_LIBRARIES := libcutils
include $(BUILD_EXECUTABLE)
diff --git a/cmds/bugreport/bugreport.c b/cmds/bugreport/bugreport.c
deleted file mode 100644
index 11e9057..0000000
--- a/cmds/bugreport/bugreport.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * Copyright (C) 2009 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 <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <cutils/properties.h>
-#include <cutils/sockets.h>
-
-int main(int argc, char *argv[]) {
- char buffer[65536];
- int i, s;
-
- /* start the dumpstate service */
- property_set("ctl.start", "dumpstate");
-
- /* socket will not be available until service starts */
- for (i = 0; i < 20; i++) {
- s = socket_local_client("dumpstate",
- ANDROID_SOCKET_NAMESPACE_RESERVED,
- SOCK_STREAM);
- if (s >= 0)
- break;
- /* try again in 1 second */
- sleep(1);
- }
-
- if (s < 0) {
- fprintf(stderr, "Failed to connect to dumpstate service\n");
- exit(1);
- }
-
- while (1) {
- int length = read(s, buffer, sizeof(buffer));
- if (length <= 0)
- break;
- fwrite(buffer, 1, length, stdout);
- }
-
- close(s);
- return 0;
-}
diff --git a/cmds/bugreport/bugreport.cpp b/cmds/bugreport/bugreport.cpp
new file mode 100644
index 0000000..b606406
--- /dev/null
+++ b/cmds/bugreport/bugreport.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2009 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 <errno.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/properties.h>
+#include <cutils/sockets.h>
+
+// This program will trigger the dumpstate service to start a call to
+// dumpstate, then connect to the dumpstate local client to read the
+// output. All of the dumpstate output is written to stdout, including
+// any errors encountered while reading/writing the output.
+int main() {
+ // Start the dumpstate service.
+ property_set("ctl.start", "dumpstate");
+
+ // Socket will not be available until service starts.
+ int s;
+ for (int i = 0; i < 20; i++) {
+ s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED,
+ SOCK_STREAM);
+ if (s >= 0)
+ break;
+ // Try again in 1 second.
+ sleep(1);
+ }
+
+ if (s == -1) {
+ printf("Failed to connect to dumpstate service: %s\n", strerror(errno));
+ return 1;
+ }
+
+ // Set a timeout so that if nothing is read in 3 minutes, we'll stop
+ // reading and quit. No timeout in dumpstate is longer than 60 seconds,
+ // so this gives lots of leeway in case of unforeseen time outs.
+ struct timeval tv;
+ tv.tv_sec = 3 * 60;
+ tv.tv_usec = 0;
+ if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
+ printf("WARNING: Cannot set socket timeout: %s\n", strerror(errno));
+ }
+
+ while (1) {
+ char buffer[65536];
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(s, buffer, sizeof(buffer)));
+ if (bytes_read == 0) {
+ break;
+ } else if (bytes_read == -1) {
+ // EAGAIN really means time out, so change the errno.
+ if (errno == EAGAIN) {
+ errno = ETIMEDOUT;
+ }
+ printf("\nBugreport read terminated abnormally (%s).\n", strerror(errno));
+ break;
+ }
+
+ ssize_t bytes_to_send = bytes_read;
+ ssize_t bytes_written;
+ do {
+ bytes_written = TEMP_FAILURE_RETRY(write(STDOUT_FILENO,
+ buffer + bytes_read - bytes_to_send,
+ bytes_to_send));
+ if (bytes_written == -1) {
+ printf("Failed to write data to stdout: read %zd, trying to send %zd (%s)\n",
+ bytes_read, bytes_to_send, strerror(errno));
+ return 1;
+ }
+ bytes_to_send -= bytes_written;
+ } while (bytes_written != 0 && bytes_to_send > 0);
+ }
+
+ TEMP_FAILURE_RETRY(close(s));
+ return 0;
+}
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index dc1ada0..a33dcf3 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -64,7 +64,8 @@ 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);
+ int fd = TEMP_FAILURE_RETRY(open(data[i].name,
+ O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
struct stat st;
if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
(time_t) st.st_mtime >= thirty_minutes_ago) {
@@ -184,7 +185,8 @@ static void dumpstate() {
if (!anr_traces_path[0]) {
printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
} else {
- int fd = open(anr_traces_path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+ int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
+ O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
if (fd < 0) {
printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
} else {
@@ -236,13 +238,15 @@ static void dumpstate() {
dump_file("LAST KMSG", "/proc/last_kmsg");
}
- dump_file("LAST PANIC CONSOLE", "/data/dontpanic/apanic_console");
- dump_file("LAST PANIC THREADS", "/data/dontpanic/apanic_threads");
+ /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
+ run_command("LAST LOGCAT", 10, "logcat", "-L", "-v", "threadtime",
+ "-b", "all", "-d", "*:v", 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("NETWORK INTERFACES", 10, "ip", "link", NULL);
run_command("IPv4 ADDRESSES", 10, "ip", "-4", "addr", "show", NULL);
run_command("IPv6 ADDRESSES", 10, "ip", "-6", "addr", "show", NULL);
@@ -387,7 +391,6 @@ static void usage() {
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: gzip output (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"
@@ -410,7 +413,6 @@ static void vibrate(FILE* vibrator, int ms) {
int main(int argc, char *argv[]) {
struct sigaction sigact;
int do_add_date = 0;
- int do_compress = 0;
int do_vibrate = 1;
char* use_outfile = 0;
int use_socket = 0;
@@ -435,7 +437,7 @@ int main(int argc, char *argv[]) {
/* set as high priority, and protect from OOM killer */
setpriority(PRIO_PROCESS, 0, -20);
- FILE *oom_adj = fopen("/proc/self/oom_adj", "w");
+ FILE *oom_adj = fopen("/proc/self/oom_adj", "we");
if (oom_adj) {
fputs("-17", oom_adj);
fclose(oom_adj);
@@ -450,7 +452,6 @@ int main(int argc, char *argv[]) {
case 's': use_socket = 1; break;
case 'v': break; // compatibility no-op
case 'q': do_vibrate = 0; break;
- case 'z': do_compress = 6; break;
case 'p': do_fb = 1; break;
case 'B': do_broadcast = 1; break;
case '?': printf("\n");
@@ -469,15 +470,14 @@ int main(int argc, char *argv[]) {
/* open the vibrator before dropping root */
FILE *vibrator = 0;
if (do_vibrate) {
- vibrator = fopen("/sys/class/timed_output/vibrator/enable", "w");
+ vibrator = fopen("/sys/class/timed_output/vibrator/enable", "we");
if (vibrator) {
- fcntl(fileno(vibrator), F_SETFD, FD_CLOEXEC);
vibrate(vibrator, 150);
}
}
/* read /proc/cmdline before dropping root */
- FILE *cmdline = fopen("/proc/cmdline", "r");
+ FILE *cmdline = fopen("/proc/cmdline", "re");
if (cmdline != NULL) {
fgets(cmdline_buf, sizeof(cmdline_buf), cmdline);
fclose(cmdline);
@@ -545,10 +545,9 @@ int main(int argc, char *argv[]) {
strlcat(screenshot_path, ".png", sizeof(screenshot_path));
}
strlcat(path, ".txt", sizeof(path));
- if (do_compress) strlcat(path, ".gz", sizeof(path));
strlcpy(tmp_path, path, sizeof(tmp_path));
strlcat(tmp_path, ".tmp", sizeof(tmp_path));
- gzip_pid = redirect_to_file(stdout, tmp_path, do_compress);
+ redirect_to_file(stdout, tmp_path);
}
dumpstate();
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 53bfff6..d17a677 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -31,7 +31,9 @@ typedef void (for_each_userid_func)(int);
/* prints the contents of a file */
int dump_file(const char *title, const char *path);
-/* prints the contents of the fd */
+/* prints the contents of the fd
+ * fd must have been opened with the flag O_NONBLOCK.
+ */
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 */
@@ -43,8 +45,8 @@ void print_properties();
/* redirect output to a service control socket */
void redirect_to_socket(FILE *redirect, const char *service);
-/* redirect output to a file, optionally gzipping; returns gzip pid */
-pid_t redirect_to_file(FILE *redirect, char *path, int gzip_level);
+/* redirect output to a file */
+void redirect_to_file(FILE *redirect, char *path);
/* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
const char *dump_traces();
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index 3e0b24b..cf14c8b 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -53,6 +53,12 @@ static const char* native_processes_to_dump[] = {
NULL,
};
+static uint64_t nanotime() {
+ struct timespec ts;
+ clock_gettime(CLOCK_MONOTONIC, &ts);
+ return (uint64_t)ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec;
+}
+
void for_each_userid(void (*func)(int), const char *header) {
DIR *d;
struct dirent *de;
@@ -98,7 +104,7 @@ static void __for_each_pid(void (*helper)(int, const char *, void *), const char
sprintf(cmdpath,"/proc/%d/cmdline", pid);
memset(cmdline, 0, sizeof(cmdline));
- if ((fd = open(cmdpath, O_RDONLY)) < 0) {
+ if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY | O_CLOEXEC))) < 0) {
strcpy(cmdline, "N/A");
} else {
read(fd, cmdline, sizeof(cmdline) - 1);
@@ -149,7 +155,7 @@ static void for_each_tid_helper(int pid, const char *cmdline, void *arg) {
sprintf(commpath,"/proc/%d/comm", tid);
memset(comm, 0, sizeof(comm));
- if ((fd = open(commpath, O_RDONLY)) < 0) {
+ if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY | O_CLOEXEC))) < 0) {
strcpy(comm, "N/A");
} else {
char *c;
@@ -180,7 +186,7 @@ void show_wchan(int pid, int tid, const char *name) {
memset(buffer, 0, sizeof(buffer));
sprintf(path, "/proc/%d/wchan", tid);
- if ((fd = open(path, O_RDONLY)) < 0) {
+ if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC))) < 0) {
printf("Failed to open '%s' (%s)\n", path, strerror(errno));
return;
}
@@ -250,22 +256,7 @@ void do_showmap(int pid, const char *name) {
run_command(title, 10, SU_PATH, "root", "showmap", arg, NULL);
}
-/* prints the contents of a file */
-int dump_file(const char *title, const char *path) {
- int fd = open(path, O_RDONLY);
- 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;
- }
- return dump_file_from_fd(title, path, fd);
-}
-
-int dump_file_from_fd(const char *title, const char *path, int fd) {
- char buffer[32768];
-
+static int _dump_file_from_fd(const char *title, const char *path, int fd) {
if (title) printf("------ %s (%s", title, path);
if (title) {
@@ -279,32 +270,126 @@ int dump_file_from_fd(const char *title, const char *path, int fd) {
printf(") ------\n");
}
- int newline = 0;
- for (;;) {
- int ret = read(fd, buffer, sizeof(buffer));
- if (ret > 0) {
- newline = (buffer[ret - 1] == '\n');
- ret = fwrite(buffer, ret, 1, stdout);
+ bool newline = false;
+ fd_set read_set;
+ struct timeval tm;
+ while (1) {
+ FD_ZERO(&read_set);
+ FD_SET(fd, &read_set);
+ /* Timeout if no data is read for 30 seconds. */
+ tm.tv_sec = 30;
+ tm.tv_usec = 0;
+ uint64_t elapsed = nanotime();
+ int ret = TEMP_FAILURE_RETRY(select(fd + 1, &read_set, NULL, NULL, &tm));
+ if (ret == -1) {
+ printf("*** %s: select failed: %s\n", path, strerror(errno));
+ newline = true;
+ break;
+ } else if (ret == 0) {
+ elapsed = nanotime() - elapsed;
+ printf("*** %s: Timed out after %.3fs\n", path,
+ (float) elapsed / NANOS_PER_SEC);
+ newline = true;
+ break;
+ } else {
+ char buffer[65536];
+ ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
+ if (bytes_read > 0) {
+ fwrite(buffer, bytes_read, 1, stdout);
+ newline = (buffer[bytes_read-1] == '\n');
+ } else {
+ if (bytes_read == -1) {
+ printf("*** %s: Failed to read from fd: %s", path, strerror(errno));
+ newline = true;
+ }
+ break;
+ }
}
- if (ret <= 0) break;
}
- close(fd);
+ TEMP_FAILURE_RETRY(close(fd));
if (!newline) printf("\n");
if (title) printf("\n");
return 0;
}
-static int64_t nanotime() {
+/* prints the contents of a file */
+int dump_file(const char *title, const char *path) {
+ 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;
+ }
+ return _dump_file_from_fd(title, path, fd);
+}
+
+/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
+ * it's possible to avoid issues where opening the file itself can get
+ * stuck.
+ */
+int dump_file_from_fd(const char *title, const char *path, int fd) {
+ int flags = fcntl(fd, F_GETFL);
+ if (flags == -1) {
+ printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
+ return -1;
+ } else if (!(flags & O_NONBLOCK)) {
+ printf("*** %s: fd must have O_NONBLOCK set.\n", path);
+ return -1;
+ }
+ return _dump_file_from_fd(title, path, fd);
+}
+
+bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) {
+ sigset_t child_mask, old_mask;
+ sigemptyset(&child_mask);
+ sigaddset(&child_mask, SIGCHLD);
+
+ if (sigprocmask(SIG_BLOCK, &child_mask, &old_mask) == -1) {
+ printf("*** sigprocmask failed: %s\n", strerror(errno));
+ return false;
+ }
+
struct timespec ts;
- clock_gettime(CLOCK_MONOTONIC, &ts);
- return (int64_t)ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec;
+ ts.tv_sec = timeout_seconds;
+ ts.tv_nsec = 0;
+ int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, NULL, &ts));
+ int saved_errno = errno;
+ // Set the signals back the way they were.
+ if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) {
+ printf("*** sigprocmask failed: %s\n", strerror(errno));
+ if (ret == 0) {
+ return false;
+ }
+ }
+ if (ret == -1) {
+ errno = saved_errno;
+ if (errno == EAGAIN) {
+ errno = ETIMEDOUT;
+ } else {
+ printf("*** sigtimedwait failed: %s\n", strerror(errno));
+ }
+ return false;
+ }
+
+ pid_t child_pid = waitpid(pid, status, WNOHANG);
+ if (child_pid != pid) {
+ if (child_pid != -1) {
+ printf("*** Waiting for pid %d, got pid %d instead\n", pid, child_pid);
+ } else {
+ printf("*** waitpid failed: %s\n", strerror(errno));
+ }
+ return false;
+ }
+ return true;
}
/* forks a command and waits for it to finish */
int run_command(const char *title, int timeout_seconds, const char *command, ...) {
fflush(stdout);
- int64_t start = nanotime();
+ uint64_t start = nanotime();
pid_t pid = fork();
/* handle error case */
@@ -345,28 +430,35 @@ int run_command(const char *title, int timeout_seconds, const char *command, ...
}
/* handle parent case */
- for (;;) {
- int status;
- pid_t p = waitpid(pid, &status, WNOHANG);
- 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: %.3fs elapsed]\n\n", command, (float)elapsed / NANOS_PER_SEC);
- return status;
+ int status;
+ bool ret = waitpid_with_timeout(pid, timeout_seconds, &status);
+ uint64_t elapsed = nanotime() - start;
+ if (!ret) {
+ if (errno == ETIMEDOUT) {
+ printf("*** %s: Timed out after %.3fs (killing pid %d)\n", command,
+ (float) elapsed / NANOS_PER_SEC, pid);
+ } else {
+ printf("*** %s: Error after %.4fs (killing pid %d)\n", command,
+ (float) elapsed / NANOS_PER_SEC, pid);
}
-
- if (timeout_seconds && elapsed / NANOS_PER_SEC > timeout_seconds) {
- printf("*** %s: Timed out after %.3fs (killing pid %d)\n", command, (float) elapsed / NANOS_PER_SEC, pid);
- kill(pid, SIGTERM);
- return -1;
+ kill(pid, SIGTERM);
+ if (!waitpid_with_timeout(pid, 5, NULL)) {
+ kill(pid, SIGKILL);
+ if (!waitpid_with_timeout(pid, 5, NULL)) {
+ printf("*** %s: Cannot kill %d even with SIGKILL.\n", command, pid);
+ }
}
+ return -1;
+ }
- usleep(100000); // poll every 0.1 sec
+ 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: %.3fs elapsed]\n\n", command, (float)elapsed / NANOS_PER_SEC);
+
+ return status;
}
size_t num_props = 0;
@@ -407,6 +499,7 @@ void redirect_to_socket(FILE *redirect, const char *service) {
fprintf(stderr, "android_get_control_socket(%s): %s\n", service, strerror(errno));
exit(1);
}
+ fcntl(s, F_SETFD, FD_CLOEXEC);
if (listen(s, 4) < 0) {
fprintf(stderr, "listen(control socket): %s\n", strerror(errno));
exit(1);
@@ -425,8 +518,8 @@ void redirect_to_socket(FILE *redirect, const char *service) {
close(fd);
}
-/* redirect output to a file, optionally gzipping; returns gzip pid (or -1) */
-pid_t redirect_to_file(FILE *redirect, char *path, int gzip_level) {
+/* redirect output to a file */
+void redirect_to_file(FILE *redirect, char *path) {
char *chp = path;
/* skip initial slash */
@@ -443,52 +536,15 @@ pid_t redirect_to_file(FILE *redirect, char *path, int gzip_level) {
}
}
- int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+ int fd = TEMP_FAILURE_RETRY(open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
+ S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH));
if (fd < 0) {
fprintf(stderr, "%s: %s\n", path, strerror(errno));
exit(1);
}
- pid_t gzip_pid = -1;
- if (gzip_level > 0) {
- int fds[2];
- if (pipe(fds)) {
- fprintf(stderr, "pipe: %s\n", strerror(errno));
- exit(1);
- }
-
- fflush(redirect);
- fflush(stdout);
-
- gzip_pid = fork();
- if (gzip_pid < 0) {
- fprintf(stderr, "fork: %s\n", strerror(errno));
- exit(1);
- }
-
- if (gzip_pid == 0) {
- dup2(fds[0], STDIN_FILENO);
- dup2(fd, STDOUT_FILENO);
-
- close(fd);
- close(fds[0]);
- close(fds[1]);
-
- char level[10];
- snprintf(level, sizeof(level), "-%d", gzip_level);
- execlp("gzip", "gzip", level, NULL);
- fprintf(stderr, "exec(gzip): %s\n", strerror(errno));
- _exit(-1);
- }
-
- close(fd);
- close(fds[0]);
- fd = fds[1];
- }
-
- dup2(fd, fileno(redirect));
+ TEMP_FAILURE_RETRY(dup2(fd, fileno(redirect)));
close(fd);
- return gzip_pid;
}
static bool should_dump_native_traces(const char* path) {
@@ -536,7 +592,8 @@ const char *dump_traces() {
}
/* create a new, empty traces.txt file to receive stack dumps */
- int fd = open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, 0666); /* -rw-rw-rw- */
+ int fd = TEMP_FAILURE_RETRY(open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
+ 0666)); /* -rw-rw-rw- */
if (fd < 0) {
fprintf(stderr, "%s: %s\n", traces_path, strerror(errno));
return NULL;
@@ -586,7 +643,7 @@ const char *dump_traces() {
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 cfd = open(path, O_RDONLY);
+ int cfd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC));
len = read(cfd, data, sizeof(data) - 1);
close(cfd);
if (len <= 0) {
@@ -598,7 +655,7 @@ const char *dump_traces() {
}
++dalvik_found;
- int64_t start = nanotime();
+ uint64_t start = nanotime();
if (kill(pid, SIGQUIT)) {
fprintf(stderr, "kill(%d, SIGQUIT): %s\n", pid, strerror(errno));
continue;
@@ -628,7 +685,7 @@ const char *dump_traces() {
fprintf(stderr, "lseek: %s\n", strerror(errno));
} else {
static uint16_t timeout_failures = 0;
- int64_t start = nanotime();
+ uint64_t start = nanotime();
/* If 3 backtrace dumps fail in a row, consider debuggerd dead. */
if (timeout_failures == 3) {
@@ -671,7 +728,7 @@ error_close_fd:
void dump_route_tables() {
const char* const RT_TABLES_PATH = "/data/misc/net/rt_tables";
dump_file("RT_TABLES", RT_TABLES_PATH);
- FILE* fp = fopen(RT_TABLES_PATH, "r");
+ FILE* fp = fopen(RT_TABLES_PATH, "re");
if (!fp) {
printf("*** %s: %s\n", RT_TABLES_PATH, strerror(errno));
return;
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index 8224e94..6dec7f6 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -1,6 +1,6 @@
LOCAL_PATH := $(call my-dir)
-common_src_files := commands.c utils.c
+common_src_files := commands.cpp utils.cpp
common_cflags := -Wall -Werror
#
@@ -12,7 +12,12 @@ LOCAL_MODULE := libinstalld
LOCAL_MODULE_TAGS := eng tests
LOCAL_SRC_FILES := $(common_src_files)
LOCAL_CFLAGS := $(common_cflags)
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ liblogwrap \
+
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+LOCAL_CLANG := true
include $(BUILD_STATIC_LIBRARY)
#
@@ -23,8 +28,15 @@ include $(CLEAR_VARS)
LOCAL_MODULE := installd
LOCAL_MODULE_TAGS := optional
LOCAL_CFLAGS := $(common_cflags)
-LOCAL_SRC_FILES := installd.c $(common_src_files)
-LOCAL_SHARED_LIBRARIES := libcutils liblog libselinux
+LOCAL_SRC_FILES := installd.cpp $(common_src_files)
+LOCAL_SHARED_LIBRARIES := \
+ libbase \
+ libcutils \
+ liblog \
+ liblogwrap \
+ libselinux \
+
LOCAL_STATIC_LIBRARIES := libdiskusage
LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+LOCAL_CLANG := true
include $(BUILD_EXECUTABLE)
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.cpp
index 76bc9d5..de6fd96 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.cpp
@@ -14,13 +14,22 @@
** limitations under the License.
*/
-#include <inttypes.h>
-#include <sys/capability.h>
#include "installd.h"
+
+#include <base/stringprintf.h>
+#include <base/logging.h>
#include <cutils/sched_policy.h>
#include <diskusage/dirsize.h>
-#include <selinux/android.h>
+#include <logwrap/logwrap.h>
#include <system/thread_defs.h>
+#include <selinux/android.h>
+
+#include <inttypes.h>
+#include <sys/capability.h>
+#include <sys/file.h>
+#include <unistd.h>
+
+using android::base::StringPrintf;
/* Directory records that are used in execution of commands. */
dir_rec_t android_data_dir;
@@ -29,34 +38,20 @@ dir_rec_t android_app_dir;
dir_rec_t android_app_private_dir;
dir_rec_t android_app_lib_dir;
dir_rec_t android_media_dir;
+dir_rec_t android_mnt_expand_dir;
dir_rec_array_t android_system_dirs;
-int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo)
-{
- char pkgdir[PKG_PATH_MAX];
- char libsymlink[PKG_PATH_MAX];
- char applibdir[PKG_PATH_MAX];
- struct stat libStat;
+static const char* kCpPath = "/system/bin/cp";
+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;
}
- if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
- ALOGE("cannot create package path\n");
- return -1;
- }
-
- if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, 0)) {
- ALOGE("cannot create package lib symlink origin path\n");
- return -1;
- }
-
- if (create_pkg_path_in_dir(applibdir, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) {
- ALOGE("cannot create package lib symlink dest path\n");
- return -1;
- }
+ std::string _pkgdir(create_package_data_path(uuid, pkgname, 0));
+ const char* pkgdir = _pkgdir.c_str();
if (mkdir(pkgdir, 0751) < 0) {
ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
@@ -68,42 +63,14 @@ int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo)
return -1;
}
- if (lstat(libsymlink, &libStat) < 0) {
- if (errno != ENOENT) {
- ALOGE("couldn't stat lib dir: %s\n", strerror(errno));
- return -1;
- }
- } else {
- if (S_ISDIR(libStat.st_mode)) {
- if (delete_dir_contents(libsymlink, 1, NULL) < 0) {
- ALOGE("couldn't delete lib directory during install for: %s", libsymlink);
- return -1;
- }
- } else if (S_ISLNK(libStat.st_mode)) {
- if (unlink(libsymlink) < 0) {
- ALOGE("couldn't unlink lib directory during install for: %s", libsymlink);
- return -1;
- }
- }
- }
-
if (selinux_android_setfilecon(pkgdir, pkgname, seinfo, uid) < 0) {
ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
- unlink(libsymlink);
unlink(pkgdir);
return -errno;
}
- if (symlink(applibdir, libsymlink) < 0) {
- ALOGE("couldn't symlink directory '%s' -> '%s': %s\n", libsymlink, applibdir,
- strerror(errno));
- unlink(pkgdir);
- return -1;
- }
-
if (chown(pkgdir, uid, gid) < 0) {
ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
- unlink(libsymlink);
unlink(pkgdir);
return -1;
}
@@ -111,12 +78,10 @@ int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo)
return 0;
}
-int uninstall(const char *pkgname, userid_t userid)
+int uninstall(const char *uuid, const char *pkgname, userid_t userid)
{
- char pkgdir[PKG_PATH_MAX];
-
- if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid))
- return -1;
+ std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
+ const char* pkgdir = _pkgdir.c_str();
remove_profile_file(pkgname);
@@ -141,21 +106,17 @@ int renamepkg(const char *oldpkgname, const char *newpkgname)
return 0;
}
-int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
+int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid)
{
- char pkgdir[PKG_PATH_MAX];
struct stat s;
- int rc = 0;
if ((uid < AID_SYSTEM) || (gid < AID_SYSTEM)) {
ALOGE("invalid uid/gid: %d %d\n", uid, gid);
return -1;
}
- if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, 0)) {
- ALOGE("cannot create package path\n");
- return -1;
- }
+ std::string _pkgdir(create_package_data_path(uuid, pkgname, 0));
+ const char* pkgdir = _pkgdir.c_str();
if (stat(pkgdir, &s) < 0) return -1;
@@ -178,35 +139,18 @@ int fix_uid(const char *pkgname, uid_t uid, gid_t gid)
return 0;
}
-int delete_user_data(const char *pkgname, userid_t userid)
+int delete_user_data(const char *uuid, const char *pkgname, userid_t userid)
{
- char pkgdir[PKG_PATH_MAX];
-
- if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid))
- return -1;
+ std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
+ const char* pkgdir = _pkgdir.c_str();
return delete_dir_contents(pkgdir, 0, NULL);
}
-int make_user_data(const char *pkgname, uid_t uid, userid_t userid, const char* seinfo)
+int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t userid, const char* seinfo)
{
- char pkgdir[PKG_PATH_MAX];
- char applibdir[PKG_PATH_MAX];
- char libsymlink[PKG_PATH_MAX];
- struct stat libStat;
-
- // Create the data dir for the package
- if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid)) {
- return -1;
- }
- if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, userid)) {
- ALOGE("cannot create package lib symlink origin path\n");
- return -1;
- }
- if (create_pkg_path_in_dir(applibdir, &android_app_lib_dir, pkgname, PKG_DIR_POSTFIX)) {
- ALOGE("cannot create package lib symlink dest path\n");
- return -1;
- }
+ std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
+ const char* pkgdir = _pkgdir.c_str();
if (mkdir(pkgdir, 0751) < 0) {
ALOGE("cannot create dir '%s': %s\n", pkgdir, strerror(errno));
@@ -218,47 +162,14 @@ int make_user_data(const char *pkgname, uid_t uid, userid_t userid, const char*
return -errno;
}
- if (lstat(libsymlink, &libStat) < 0) {
- if (errno != ENOENT) {
- ALOGE("couldn't stat lib dir for non-primary: %s\n", strerror(errno));
- unlink(pkgdir);
- return -1;
- }
- } else {
- if (S_ISDIR(libStat.st_mode)) {
- if (delete_dir_contents(libsymlink, 1, NULL) < 0) {
- ALOGE("couldn't delete lib directory during install for non-primary: %s",
- libsymlink);
- unlink(pkgdir);
- return -1;
- }
- } else if (S_ISLNK(libStat.st_mode)) {
- if (unlink(libsymlink) < 0) {
- ALOGE("couldn't unlink lib directory during install for non-primary: %s",
- libsymlink);
- unlink(pkgdir);
- return -1;
- }
- }
- }
-
if (selinux_android_setfilecon(pkgdir, pkgname, seinfo, uid) < 0) {
ALOGE("cannot setfilecon dir '%s': %s\n", pkgdir, strerror(errno));
- unlink(libsymlink);
unlink(pkgdir);
return -errno;
}
- if (symlink(applibdir, libsymlink) < 0) {
- ALOGE("couldn't symlink directory for non-primary '%s' -> '%s': %s\n", libsymlink,
- applibdir, strerror(errno));
- unlink(pkgdir);
- return -1;
- }
-
if (chown(pkgdir, uid, uid) < 0) {
ALOGE("cannot chown dir '%s': %s\n", pkgdir, strerror(errno));
- unlink(libsymlink);
unlink(pkgdir);
return -errno;
}
@@ -266,6 +177,80 @@ int make_user_data(const char *pkgname, uid_t uid, userid_t userid, const char*
return 0;
}
+int move_user_data(const char *from_uuid, const char *to_uuid,
+ const char *package_name, appid_t appid, const char* seinfo) {
+ std::vector<userid_t> users = get_known_users(from_uuid);
+
+ // Copy package private data for all known users
+ for (auto user : users) {
+ std::string from(create_package_data_path(from_uuid, package_name, user));
+ std::string to(create_package_data_path(to_uuid, package_name, user));
+ std::string to_user(create_data_user_path(to_uuid, user));
+
+ // Data source may not exist for all users; that's okay
+ if (access(from.c_str(), F_OK) != 0) {
+ LOG(INFO) << "Missing source " << from;
+ continue;
+ }
+
+ std::string user_path(create_data_user_path(to_uuid, user));
+ if (fs_prepare_dir(user_path.c_str(), 0771, AID_SYSTEM, AID_SYSTEM) != 0) {
+ LOG(ERROR) << "Failed to prepare user target " << user_path;
+ goto fail;
+ }
+
+ uid_t uid = multiuser_get_uid(user, appid);
+ if (make_user_data(to_uuid, package_name, uid, user, seinfo) != 0) {
+ LOG(ERROR) << "Failed to create package target " << to;
+ goto fail;
+ }
+
+ char *argv[] = {
+ (char*) kCpPath,
+ (char*) "-F", /* delete any existing destination file first (--remove-destination) */
+ (char*) "-p", /* preserve timestamps, ownership, and permissions */
+ (char*) "-R", /* recurse into subdirectories (DEST must be a directory) */
+ (char*) "-P", /* Do not follow symlinks [default] */
+ (char*) "-d", /* don't dereference symlinks */
+ (char*) from.c_str(),
+ (char*) to_user.c_str()
+ };
+
+ LOG(DEBUG) << "Copying " << from << " to " << to;
+ int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+
+ if (rc != 0) {
+ LOG(ERROR) << "Failed copying " << from << " to " << to
+ << ": status " << rc;
+ goto fail;
+ }
+
+ if (restorecon_data(to_uuid, package_name, seinfo, uid) != 0) {
+ LOG(ERROR) << "Failed to restorecon " << to;
+ goto fail;
+ }
+ }
+
+ // Copy successful, so delete old data
+ for (auto user : users) {
+ std::string from(create_package_data_path(from_uuid, package_name, user));
+ if (delete_dir_contents(from.c_str(), 1, NULL) != 0) {
+ LOG(WARNING) << "Failed to delete " << from;
+ }
+ }
+ return 0;
+
+fail:
+ // Nuke everything we might have already copied
+ for (auto user : users) {
+ std::string to(create_package_data_path(to_uuid, package_name, user));
+ if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+ LOG(WARNING) << "Failed to rollback " << to;
+ }
+ }
+ return -1;
+}
+
int make_user_config(userid_t userid)
{
if (ensure_config_user_dirs(userid) == -1) {
@@ -275,49 +260,49 @@ int make_user_config(userid_t userid)
return 0;
}
-int delete_user(userid_t userid)
+int delete_user(const char *uuid, userid_t userid)
{
int status = 0;
- char data_path[PKG_PATH_MAX];
- if ((create_user_path(data_path, userid) != 0)
- || (delete_dir_contents(data_path, 1, NULL) != 0)) {
+ std::string data_path(create_data_user_path(uuid, userid));
+ if (delete_dir_contents(data_path.c_str(), 1, NULL) != 0) {
status = -1;
}
- char media_path[PATH_MAX];
- if ((create_user_media_path(media_path, userid) != 0)
- || (delete_dir_contents(media_path, 1, NULL) != 0)) {
+ std::string media_path(create_data_media_path(uuid, userid));
+ if (delete_dir_contents(media_path.c_str(), 1, NULL) != 0) {
status = -1;
}
- char config_path[PATH_MAX];
- if ((create_user_config_path(config_path, userid) != 0)
- || (delete_dir_contents(config_path, 1, NULL) != 0)) {
- status = -1;
+ // 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;
+ }
}
return status;
}
-int delete_cache(const char *pkgname, userid_t userid)
+int delete_cache(const char *uuid, const char *pkgname, userid_t userid)
{
- char cachedir[PKG_PATH_MAX];
-
- if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, userid))
- return -1;
+ std::string _cachedir(
+ create_package_data_path(uuid, pkgname, userid) + CACHE_DIR_POSTFIX);
+ const char* cachedir = _cachedir.c_str();
/* delete contents, not the directory, no exceptions */
return delete_dir_contents(cachedir, 0, NULL);
}
-int delete_code_cache(const char *pkgname, userid_t userid)
+int delete_code_cache(const char *uuid, const char *pkgname, userid_t userid)
{
- char codecachedir[PKG_PATH_MAX];
- struct stat s;
+ std::string _codecachedir(
+ create_package_data_path(uuid, pkgname, userid) + CACHE_DIR_POSTFIX);
+ const char* codecachedir = _codecachedir.c_str();
- if (create_pkg_path(codecachedir, pkgname, CODE_CACHE_DIR_POSTFIX, userid))
- return -1;
+ struct stat s;
/* it's okay if code cache is missing */
if (lstat(codecachedir, &s) == -1 && errno == ENOENT) {
@@ -335,7 +320,7 @@ int delete_code_cache(const char *pkgname, userid_t userid)
* also require that apps constantly modify file metadata even
* when just reading from the cache, which is pretty awful.
*/
-int free_cache(int64_t free_size)
+int free_cache(const char *uuid, int64_t free_size)
{
cache_t* cache;
int64_t avail;
@@ -344,7 +329,9 @@ int free_cache(int64_t free_size)
char tmpdir[PATH_MAX];
char *dirpos;
- avail = data_disk_free();
+ std::string data_path(create_data_path(uuid));
+
+ avail = data_disk_free(data_path);
if (avail < 0) return -1;
ALOGI("free_cache(%" PRId64 ") avail %" PRId64 "\n", free_size, avail);
@@ -352,15 +339,16 @@ int free_cache(int64_t free_size)
cache = start_cache_collection();
- // Collect cache files for primary user.
- if (create_user_path(tmpdir, 0) == 0) {
- //ALOGI("adding cache files from %s\n", tmpdir);
- add_cache_files(cache, tmpdir, "cache");
+ // Special case for owner on internal storage
+ if (uuid == nullptr) {
+ std::string _tmpdir(create_data_user_path(nullptr, 0));
+ add_cache_files(cache, _tmpdir.c_str(), "cache");
}
// Search for other users and add any cache files from them.
- snprintf(tmpdir, sizeof(tmpdir), "%s%s", android_data_dir.path,
- SECONDARY_USER_PREFIX);
+ std::string _tmpdir(create_data_path(uuid) + "/" + SECONDARY_USER_PREFIX);
+ strcpy(tmpdir, _tmpdir.c_str());
+
dirpos = tmpdir + strlen(tmpdir);
d = opendir(tmpdir);
if (d != NULL) {
@@ -412,10 +400,10 @@ int free_cache(int64_t free_size)
closedir(d);
}
- clear_cache_files(cache, free_size);
+ clear_cache_files(data_path, cache, free_size);
finish_cache_collection(cache);
- return data_disk_free() >= free_size ? 0 : -1;
+ return data_disk_free(data_path) >= free_size ? 0 : -1;
}
int move_dex(const char *src, const char *dst, const char *instruction_set)
@@ -466,7 +454,7 @@ int rm_dex(const char *path, const char *instruction_set)
}
}
-int get_size(const char *pkgname, userid_t userid, const char *apkpath,
+int get_size(const char *uuid, const char *pkgname, userid_t userid, const char *apkpath,
const char *libdirpath, const char *fwdlock_apkpath, const char *asecpath,
const char *instruction_set, int64_t *_codesize, int64_t *_datasize,
int64_t *_cachesize, int64_t* _asecsize)
@@ -523,11 +511,10 @@ int get_size(const char *pkgname, userid_t userid, const char *apkpath,
}
}
- if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, userid)) {
- goto done;
- }
+ std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
+ const char* pkgdir = _pkgdir.c_str();
- d = opendir(path);
+ d = opendir(pkgdir);
if (d == NULL) {
goto done;
}
@@ -625,30 +612,40 @@ int create_cache_path(char path[PKG_PATH_MAX], const char *src, const char *inst
return 0;
}
-static void run_dexopt(int zip_fd, int odex_fd, const char* input_file_name,
- const char* output_file_name)
+static int split_count(const char *str)
{
- /* platform-specific flags affecting optimization and verification */
- char dexopt_flags[PROPERTY_VALUE_MAX];
- property_get("dalvik.vm.dexopt-flags", dexopt_flags, "");
- ALOGV("dalvik.vm.dexopt-flags=%s\n", dexopt_flags);
+ char *ctx;
+ int count = 0;
+ char buf[PROPERTY_VALUE_MAX];
- static const char* DEX_OPT_BIN = "/system/bin/dexopt";
- static const int MAX_INT_LEN = 12; // '-'+10dig+'\0' -OR- 0x+8dig
- char zip_num[MAX_INT_LEN];
- char odex_num[MAX_INT_LEN];
+ strncpy(buf, str, sizeof(buf));
+ char *pBuf = buf;
- sprintf(zip_num, "%d", zip_fd);
- sprintf(odex_num, "%d", odex_fd);
+ while(strtok_r(pBuf, " ", &ctx) != NULL) {
+ count++;
+ pBuf = NULL;
+ }
- ALOGV("Running %s in=%s out=%s\n", DEX_OPT_BIN, input_file_name, output_file_name);
- execl(DEX_OPT_BIN, DEX_OPT_BIN, "--zip", zip_num, odex_num, input_file_name,
- dexopt_flags, (char*) NULL);
- ALOGE("execl(%s) failed: %s\n", DEX_OPT_BIN, strerror(errno));
+ return count;
+}
+
+static int split(char *buf, const char **argv)
+{
+ char *ctx;
+ int count = 0;
+ char *tok;
+ char *pBuf = buf;
+
+ while((tok = strtok_r(pBuf, " ", &ctx)) != NULL) {
+ argv[count++] = tok;
+ pBuf = NULL;
+ }
+
+ return count;
}
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)
+ const char* output_file_name, const char *pkgname __unused, 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;
@@ -670,7 +667,7 @@ static void run_patchoat(int input_fd, int oat_fd, const char* input_file_name,
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",
+ ALOGV("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 */
@@ -689,7 +686,7 @@ static void run_patchoat(int input_fd, int oat_fd, const char* input_file_name,
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,
- bool vm_safe_mode)
+ bool vm_safe_mode, bool debuggable)
{
static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
@@ -712,14 +709,32 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
bool have_dex2oat_compiler_filter_flag = property_get("dalvik.vm.dex2oat-filter",
dex2oat_compiler_filter_flag, NULL) > 0;
+ char dex2oat_threads_buf[PROPERTY_VALUE_MAX];
+ bool have_dex2oat_threads_flag = property_get("dalvik.vm.dex2oat-threads", dex2oat_threads_buf,
+ NULL) > 0;
+ char dex2oat_threads_arg[PROPERTY_VALUE_MAX + 2];
+ if (have_dex2oat_threads_flag) {
+ sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf);
+ }
+
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_isa_variant_key[PROPERTY_KEY_MAX];
+ sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set);
+ char dex2oat_isa_variant[PROPERTY_VALUE_MAX];
+ bool have_dex2oat_isa_variant = property_get(dex2oat_isa_variant_key,
+ dex2oat_isa_variant, NULL) > 0;
+
+ const char *dex2oat_norelocation = "-Xnorelocate";
+ bool have_dex2oat_relocation_skip_flag = false;
+
char dex2oat_flags[PROPERTY_VALUE_MAX];
- bool have_dex2oat_flags = property_get("dalvik.vm.dex2oat-flags", dex2oat_flags, NULL) > 0;
+ int dex2oat_flags_count = property_get("dalvik.vm.dex2oat-flags",
+ dex2oat_flags, NULL) <= 0 ? 0 : split_count(dex2oat_flags);
ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags);
// If we booting without the real /data, don't spend time compiling.
@@ -729,6 +744,10 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
(strcmp(vold_decrypt, "trigger_restart_min_framework") == 0 ||
(strcmp(vold_decrypt, "1") == 0)));
+ char use_jit_property[PROPERTY_VALUE_MAX];
+ bool have_jit_property = property_get("debug.usejit", use_jit_property, NULL) > 0;
+ bool use_jit = have_jit_property && strcmp(use_jit_property, "true") == 0;
+
static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
static const char* RUNTIME_ARG = "--runtime-arg";
@@ -740,6 +759,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
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_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];
@@ -754,6 +774,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* 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_variant_arg, "--instruction-set-variant=%s", dex2oat_isa_variant);
sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features);
if (swap_fd >= 0) {
have_dex2oat_swap_fd = true;
@@ -787,31 +808,49 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
if (skip_compilation) {
strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=verify-none");
have_dex2oat_compiler_filter_flag = true;
+ have_dex2oat_relocation_skip_flag = true;
} else if (vm_safe_mode) {
strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=interpret-only");
have_dex2oat_compiler_filter_flag = true;
+ } else if (use_jit) {
+ strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=verify-at-runtime");
+ 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);
}
+ // Check whether all apps should be compiled debuggable.
+ if (!debuggable) {
+ debuggable =
+ (property_get("dalvik.vm.always_debuggable", prop_buf, "0") > 0) &&
+ (prop_buf[0] == '1');
+ }
+
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)
- + (have_dex2oat_swap_fd ? 1 : 0)];
+ 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)
+ + (have_dex2oat_threads_flag ? 1 : 0)
+ + (have_dex2oat_swap_fd ? 1 : 0)
+ + (have_dex2oat_relocation_skip_flag ? 2 : 0)
+ + (debuggable ? 1 : 0)
+ + dex2oat_flags_count];
int i = 0;
- argv[i++] = (char*)DEX2OAT_BIN;
+ argv[i++] = DEX2OAT_BIN;
argv[i++] = zip_fd_arg;
argv[i++] = zip_location_arg;
argv[i++] = oat_fd_arg;
argv[i++] = oat_location_arg;
argv[i++] = instruction_set_arg;
+ if (have_dex2oat_isa_variant) {
+ argv[i++] = instruction_set_variant_arg;
+ }
if (have_dex2oat_isa_features) {
argv[i++] = instruction_set_features_arg;
}
@@ -822,27 +861,37 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
argv[i++] = top_k_profile_threshold_arg;
}
if (have_dex2oat_Xms_flag) {
- argv[i++] = (char*)RUNTIME_ARG;
+ argv[i++] = RUNTIME_ARG;
argv[i++] = dex2oat_Xms_arg;
}
if (have_dex2oat_Xmx_flag) {
- argv[i++] = (char*)RUNTIME_ARG;
+ argv[i++] = 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;
+ if (have_dex2oat_threads_flag) {
+ argv[i++] = dex2oat_threads_arg;
}
if (have_dex2oat_swap_fd) {
argv[i++] = dex2oat_swap_fd;
}
+ if (debuggable) {
+ argv[i++] = "--debuggable";
+ }
+ if (dex2oat_flags_count) {
+ i += split(dex2oat_flags, argv + i);
+ }
+ if (have_dex2oat_relocation_skip_flag) {
+ argv[i++] = RUNTIME_ARG;
+ argv[i++] = dex2oat_norelocation;
+ }
// Do not add after dex2oat_flags, they should override others for debugging.
argv[i] = NULL;
- execv(DEX2OAT_BIN, (char* const *)argv);
- ALOGE("execl(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
+ execv(DEX2OAT_BIN, (char * const *)argv);
+ ALOGE("execv(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno));
}
static int wait_child(pid_t pid)
@@ -888,16 +937,50 @@ static bool ShouldUseSwapFileForDexopt() {
return (strcmp(low_mem_buf, "true") == 0);
}
+/*
+ * Computes the odex file for the given apk_path and instruction_set.
+ * /system/framework/whatever.jar -> /system/framework/oat/<isa>/whatever.odex
+ *
+ * Returns false if it failed to determine the odex file path.
+ */
+static bool calculate_odex_file_path(char path[PKG_PATH_MAX],
+ const char *apk_path,
+ const char *instruction_set)
+{
+ if (strlen(apk_path) + strlen("oat/") + strlen(instruction_set)
+ + strlen("/") + strlen("odex") + 1 > PKG_PATH_MAX) {
+ ALOGE("apk_path '%s' may be too long to form odex file path.\n", apk_path);
+ return false;
+ }
+
+ strcpy(path, apk_path);
+ char *end = strrchr(path, '/');
+ if (end == NULL) {
+ ALOGE("apk_path '%s' has no '/'s in it?!\n", apk_path);
+ return false;
+ }
+ const char *apk_end = apk_path + (end - path); // strrchr(apk_path, '/');
+
+ strcpy(end + 1, "oat/"); // path = /system/framework/oat/\0
+ strcat(path, instruction_set); // path = /system/framework/oat/<isa>\0
+ strcat(path, apk_end); // path = /system/framework/oat/<isa>/whatever.jar\0
+ end = strrchr(path, '.');
+ if (end == NULL) {
+ ALOGE("apk_path '%s' has no extension.\n", apk_path);
+ return false;
+ }
+ strcpy(end + 1, "odex");
+ return true;
+}
+
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)
+ const char *pkgname, const char *instruction_set, int dexopt_needed,
+ bool vm_safe_mode, bool debuggable, const char* oat_dir)
{
struct utimbuf ut;
- struct stat input_stat, dex_stat;
+ struct stat input_stat;
char out_path[PKG_PATH_MAX];
- char persist_sys_dalvik_vm_lib[PROPERTY_VALUE_MAX];
char swap_file_name[PKG_PATH_MAX];
- char *end;
const char *input_file;
char in_odex_path[PKG_PATH_MAX];
int res, input_fd=-1, out_fd=-1, swap_fd=-1;
@@ -906,55 +989,43 @@ int dexopt(const char *apk_path, uid_t uid, bool is_public,
// Note: the cache path will require an additional 5 bytes for ".swap", but we'll try to run
// without a swap file, if necessary.
if (strlen(apk_path) >= (PKG_PATH_MAX - 8)) {
+ ALOGE("apk_path too long '%s'\n", apk_path);
return -1;
}
- /* 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 && !is_patchoat) {
- strcpy(end, ".odex");
- if (stat(out_path, &dex_stat) == 0) {
- return 0;
- }
- }
-
- if (create_cache_path(out_path, apk_path, instruction_set)) {
- return -1;
- }
-
- 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);
+ if (oat_dir != NULL && oat_dir[0] != '!') {
+ if (validate_apk_path(oat_dir)) {
+ ALOGE("invalid oat_dir '%s'\n", oat_dir);
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) {
+ if (calculate_oat_file_path(out_path, oat_dir, apk_path, instruction_set)) {
return -1;
}
- strcpy(end + 1, "odex");
- input_file = in_odex_path;
} else {
- input_file = apk_path;
+ if (create_cache_path(out_path, apk_path, instruction_set)) {
+ return -1;
+ }
+ }
+
+ switch (dexopt_needed) {
+ case DEXOPT_DEX2OAT_NEEDED:
+ input_file = apk_path;
+ break;
+
+ case DEXOPT_PATCHOAT_NEEDED:
+ if (!calculate_odex_file_path(in_odex_path, apk_path, instruction_set)) {
+ return -1;
+ }
+ input_file = in_odex_path;
+ break;
+
+ case DEXOPT_SELF_PATCHOAT_NEEDED:
+ input_file = out_path;
+ break;
+
+ default:
+ ALOGE("Invalid dexopt needed: %d\n", dexopt_needed);
+ exit(72);
}
memset(&input_stat, 0, sizeof(input_stat));
@@ -989,7 +1060,7 @@ int dexopt(const char *apk_path, uid_t uid, bool is_public,
}
// Create a swap file if necessary.
- if (!is_patchoat && ShouldUseSwapFileForDexopt()) {
+ if (ShouldUseSwapFileForDexopt()) {
// Make sure there really is enough space.
size_t out_len = strlen(out_path);
if (out_len + strlen(".swap") + 1 <= PKG_PATH_MAX) {
@@ -1048,17 +1119,21 @@ int dexopt(const char *apk_path, uid_t uid, bool is_public,
exit(67);
}
- if (strncmp(persist_sys_dalvik_vm_lib, "libdvm", 6) == 0) {
- run_dexopt(input_fd, out_fd, input_file, out_path);
- } else if (strncmp(persist_sys_dalvik_vm_lib, "libart", 6) == 0) {
- if (is_patchoat) {
- run_patchoat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set);
+ if (dexopt_needed == DEXOPT_PATCHOAT_NEEDED
+ || dexopt_needed == DEXOPT_SELF_PATCHOAT_NEEDED) {
+ run_patchoat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set);
+ } else if (dexopt_needed == DEXOPT_DEX2OAT_NEEDED) {
+ const char *input_file_name = strrchr(input_file, '/');
+ if (input_file_name == NULL) {
+ input_file_name = input_file;
} else {
- run_dex2oat(input_fd, out_fd, input_file, out_path, swap_fd, pkgname,
- instruction_set, vm_safe_mode);
+ input_file_name++;
}
+ run_dex2oat(input_fd, out_fd, input_file_name, out_path, swap_fd, pkgname,
+ instruction_set, vm_safe_mode, debuggable);
} else {
- exit(69); /* Unexpected persist.sys.dalvik.vm.lib value */
+ ALOGE("Invalid dexopt needed: %d\n", dexopt_needed);
+ exit(73);
}
exit(68); /* only get here on exec failure */
} else {
@@ -1368,21 +1443,16 @@ done:
return 0;
}
-int linklib(const char* pkgname, const char* asecLibDir, int userId)
+int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId)
{
- char pkgdir[PKG_PATH_MAX];
- char libsymlink[PKG_PATH_MAX];
struct stat s, libStat;
int rc = 0;
- if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userId)) {
- ALOGE("cannot create package path\n");
- return -1;
- }
- if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, userId)) {
- ALOGE("cannot create package lib symlink origin path\n");
- return -1;
- }
+ std::string _pkgdir(create_package_data_path(uuid, pkgname, userId));
+ std::string _libsymlink(_pkgdir + PKG_LIB_POSTFIX);
+
+ const char* pkgdir = _pkgdir.c_str();
+ const char* libsymlink = _libsymlink.c_str();
if (stat(pkgdir, &s) < 0) return -1;
@@ -1551,14 +1621,12 @@ fail:
return -1;
}
-int restorecon_data(const char* pkgName, const char* seinfo, uid_t uid)
+int restorecon_data(const char* uuid, const char* pkgName,
+ const char* seinfo, uid_t uid)
{
struct dirent *entry;
DIR *d;
struct stat s;
- char *userdir;
- char *primarydir;
- char *pkgdir;
int ret = 0;
// SELINUX_ANDROID_RESTORECON_DATADATA flag is set by libselinux. Not needed here.
@@ -1569,26 +1637,20 @@ int restorecon_data(const char* pkgName, const char* seinfo, uid_t uid)
return -1;
}
- if (asprintf(&primarydir, "%s%s%s", android_data_dir.path, PRIMARY_USER_PREFIX, pkgName) < 0) {
- return -1;
- }
-
- // Relabel for primary user.
- if (selinux_android_restorecon_pkgdir(primarydir, seinfo, uid, flags) < 0) {
- ALOGE("restorecon failed for %s: %s\n", primarydir, strerror(errno));
- ret |= -1;
- }
+ // Special case for owner on internal storage
+ if (uuid == nullptr) {
+ std::string path(create_package_data_path(nullptr, pkgName, 0));
- if (asprintf(&userdir, "%s%s", android_data_dir.path, SECONDARY_USER_PREFIX) < 0) {
- free(primarydir);
- return -1;
+ if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, flags) < 0) {
+ PLOG(ERROR) << "restorecon failed for " << path;
+ ret |= -1;
+ }
}
// Relabel package directory for all secondary users.
- d = opendir(userdir);
+ std::string userdir(create_data_path(uuid) + "/" + SECONDARY_USER_PREFIX);
+ d = opendir(userdir.c_str());
if (d == NULL) {
- free(primarydir);
- free(userdir);
return -1;
}
@@ -1609,25 +1671,75 @@ int restorecon_data(const char* pkgName, const char* seinfo, uid_t uid)
continue;
}
- if (asprintf(&pkgdir, "%s%s/%s", userdir, user, pkgName) < 0) {
- continue;
- }
-
- if (stat(pkgdir, &s) < 0) {
- free(pkgdir);
+ 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, seinfo, uid, flags) < 0) {
- ALOGE("restorecon failed for %s: %s\n", pkgdir, strerror(errno));
+ if (selinux_android_restorecon_pkgdir(pkgdir.c_str(), seinfo, s.st_uid, flags) < 0) {
+ PLOG(ERROR) << "restorecon failed for " << pkgdir;
ret |= -1;
}
- free(pkgdir);
}
closedir(d);
- free(primarydir);
- free(userdir);
return ret;
}
+int create_oat_dir(const char* oat_dir, const char* instruction_set)
+{
+ char oat_instr_dir[PKG_PATH_MAX];
+
+ if (validate_apk_path(oat_dir)) {
+ ALOGE("invalid apk path '%s' (bad prefix)\n", oat_dir);
+ return -1;
+ }
+ if (fs_prepare_dir(oat_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) {
+ return -1;
+ }
+ if (selinux_android_restorecon(oat_dir, 0)) {
+ ALOGE("cannot restorecon dir '%s': %s\n", oat_dir, strerror(errno));
+ return -1;
+ }
+ snprintf(oat_instr_dir, PKG_PATH_MAX, "%s/%s", oat_dir, instruction_set);
+ if (fs_prepare_dir(oat_instr_dir, S_IRWXU | S_IRWXG | S_IXOTH, AID_SYSTEM, AID_INSTALL)) {
+ return -1;
+ }
+ return 0;
+}
+
+int rm_package_dir(const char* apk_path)
+{
+ if (validate_apk_path(apk_path)) {
+ ALOGE("invalid apk path '%s' (bad prefix)\n", apk_path);
+ return -1;
+ }
+ return delete_dir_contents(apk_path, 1 /* also_delete_dir */ , NULL /* exclusion_predicate */);
+}
+
+int calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
+ const char *instruction_set) {
+ char *file_name_start;
+ char *file_name_end;
+
+ file_name_start = strrchr(apk_path, '/');
+ if (file_name_start == NULL) {
+ ALOGE("apk_path '%s' has no '/'s in it\n", apk_path);
+ return -1;
+ }
+ file_name_end = strrchr(apk_path, '.');
+ if (file_name_end < file_name_start) {
+ ALOGE("apk_path '%s' has no extension\n", apk_path);
+ return -1;
+ }
+
+ // Calculate file_name
+ int file_name_len = file_name_end - file_name_start - 1;
+ char file_name[file_name_len + 1];
+ memcpy(file_name, file_name_start + 1, file_name_len);
+ file_name[file_name_len] = '\0';
+
+ // <apk_parent_dir>/oat/<isa>/<file_name>.odex
+ snprintf(path, PKG_PATH_MAX, "%s/%s/%s.odex", oat_dir, instruction_set, file_name);
+ return 0;
+}
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.cpp
index 5b8a1e3..3a86181 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.cpp
@@ -1,90 +1,101 @@
/*
** 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.
*/
+#include "installd.h"
+
+#include <base/logging.h>
+
#include <sys/capability.h>
#include <sys/prctl.h>
#include <selinux/android.h>
#include <selinux/avc.h>
-#include "installd.h"
-
-
#define BUFFER_MAX 1024 /* input buffer for commands */
-#define TOKEN_MAX 8 /* max number of arguments in buffer */
+#define TOKEN_MAX 16 /* max number of arguments in buffer */
#define REPLY_MAX 256 /* largest reply allowed */
-static int do_ping(char **arg, char reply[REPLY_MAX])
+static char* parse_null(char* arg) {
+ if (strcmp(arg, "!") == 0) {
+ return nullptr;
+ } else {
+ return arg;
+ }
+}
+
+static int do_ping(char **arg __unused, char reply[REPLY_MAX] __unused)
{
return 0;
}
-static int do_install(char **arg, char reply[REPLY_MAX])
+static int do_install(char **arg, char reply[REPLY_MAX] __unused)
{
- return install(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3]); /* pkgname, uid, gid, seinfo */
+ return install(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), arg[4]); /* uuid, pkgname, uid, gid, seinfo */
}
-static int do_dexopt(char **arg, char reply[REPLY_MAX])
+static int do_dexopt(char **arg, char reply[REPLY_MAX] __unused)
{
- /* 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);
+ /* apk_path, uid, is_public, pkgname, instruction_set,
+ * dexopt_needed, vm_safe_mode, debuggable, oat_dir */
+ return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3], arg[4], atoi(arg[5]),
+ atoi(arg[6]), atoi(arg[7]), arg[8]);
}
-static int do_mark_boot_complete(char **arg, char reply[REPLY_MAX])
+static int do_mark_boot_complete(char **arg, char reply[REPLY_MAX] __unused)
{
return mark_boot_complete(arg[0] /* instruction set */);
}
-static int do_move_dex(char **arg, char reply[REPLY_MAX])
+static int do_move_dex(char **arg, char reply[REPLY_MAX] __unused)
{
return move_dex(arg[0], arg[1], arg[2]); /* src, dst, instruction_set */
}
-static int do_rm_dex(char **arg, char reply[REPLY_MAX])
+static int do_rm_dex(char **arg, char reply[REPLY_MAX] __unused)
{
return rm_dex(arg[0], arg[1]); /* pkgname, instruction_set */
}
-static int do_remove(char **arg, char reply[REPLY_MAX])
+static int do_remove(char **arg, char reply[REPLY_MAX] __unused)
{
- return uninstall(arg[0], atoi(arg[1])); /* pkgname, userid */
+ return uninstall(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */
}
-static int do_rename(char **arg, char reply[REPLY_MAX])
+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])
+static int do_fixuid(char **arg, char reply[REPLY_MAX] __unused)
{
- return fix_uid(arg[0], atoi(arg[1]), atoi(arg[2])); /* pkgname, uid, gid */
+ return fix_uid(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3])); /* uuid, pkgname, uid, gid */
}
-static int do_free_cache(char **arg, char reply[REPLY_MAX]) /* TODO int:free_size */
+static int do_free_cache(char **arg, char reply[REPLY_MAX] __unused) /* TODO int:free_size */
{
- return free_cache((int64_t)atoll(arg[0])); /* free_size */
+ return free_cache(parse_null(arg[0]), (int64_t)atoll(arg[1])); /* uuid, free_size */
}
-static int do_rm_cache(char **arg, char reply[REPLY_MAX])
+static int do_rm_cache(char **arg, char reply[REPLY_MAX] __unused)
{
- return delete_cache(arg[0], atoi(arg[1])); /* pkgname, userid */
+ return delete_cache(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */
}
-static int do_rm_code_cache(char **arg, char reply[REPLY_MAX])
+static int do_rm_code_cache(char **arg, char reply[REPLY_MAX] __unused)
{
- return delete_code_cache(arg[0], atoi(arg[1])); /* pkgname, userid */
+ return delete_code_cache(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */
}
static int do_get_size(char **arg, char reply[REPLY_MAX])
@@ -95,9 +106,9 @@ static int do_get_size(char **arg, char reply[REPLY_MAX])
int64_t asecsize = 0;
int res = 0;
- /* pkgdir, userid, apkpath */
- res = get_size(arg[0], atoi(arg[1]), arg[2], arg[3], arg[4], arg[5],
- arg[6], &codesize, &datasize, &cachesize, &asecsize);
+ /* uuid, pkgdir, userid, apkpath */
+ res = get_size(parse_null(arg[0]), arg[1], atoi(arg[2]), arg[3], arg[4], arg[5], arg[6],
+ arg[7], &codesize, &datasize, &cachesize, &asecsize);
/*
* Each int64_t can take up 22 characters printed out. Make sure it
@@ -108,51 +119,64 @@ static int do_get_size(char **arg, char reply[REPLY_MAX])
return res;
}
-static int do_rm_user_data(char **arg, char reply[REPLY_MAX])
+static int do_rm_user_data(char **arg, char reply[REPLY_MAX] __unused)
{
- return delete_user_data(arg[0], atoi(arg[1])); /* pkgname, userid */
+ return delete_user_data(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */
}
-static int do_mk_user_data(char **arg, char reply[REPLY_MAX])
+static int do_mv_user_data(char **arg, char reply[REPLY_MAX] __unused)
{
- return make_user_data(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3]);
- /* pkgname, uid, userid, seinfo */
+ // from_uuid, to_uuid, pkgname, appid, seinfo
+ return move_user_data(parse_null(arg[0]), parse_null(arg[1]), arg[2], atoi(arg[3]), arg[4]);
}
-static int do_mk_user_config(char **arg, char reply[REPLY_MAX])
+static int do_mk_user_data(char **arg, char reply[REPLY_MAX] __unused)
+{
+ return make_user_data(parse_null(arg[0]), arg[1], atoi(arg[2]), atoi(arg[3]), arg[4]);
+ /* uuid, pkgname, uid, userid, seinfo */
+}
+
+static int do_mk_user_config(char **arg, char reply[REPLY_MAX] __unused)
{
return make_user_config(atoi(arg[0])); /* userid */
}
-static int do_rm_user(char **arg, char reply[REPLY_MAX])
+static int do_rm_user(char **arg, char reply[REPLY_MAX] __unused)
{
- return delete_user(atoi(arg[0])); /* userid */
+ return delete_user(parse_null(arg[0]), atoi(arg[1])); /* uuid, userid */
}
-static int do_movefiles(char **arg, char reply[REPLY_MAX])
+static int do_movefiles(char **arg __unused, char reply[REPLY_MAX] __unused)
{
return movefiles();
}
-static int do_linklib(char **arg, char reply[REPLY_MAX])
+static int do_linklib(char **arg, char reply[REPLY_MAX] __unused)
{
- return linklib(arg[0], arg[1], atoi(arg[2]));
+ return linklib(parse_null(arg[0]), arg[1], arg[2], atoi(arg[3]));
}
-static int do_idmap(char **arg, char reply[REPLY_MAX])
+static int do_idmap(char **arg, char reply[REPLY_MAX] __unused)
{
return idmap(arg[0], arg[1], atoi(arg[2]));
}
static int do_restorecon_data(char **arg, char reply[REPLY_MAX] __attribute__((unused)))
{
- return restorecon_data(arg[0], arg[1], atoi(arg[2]));
- /* pkgName, seinfo, uid*/
+ return restorecon_data(parse_null(arg[0]), arg[1], arg[2], atoi(arg[3]));
+ /* uuid, pkgName, seinfo, uid*/
+}
+
+static int do_create_oat_dir(char **arg, char reply[REPLY_MAX] __unused)
+{
+ /* oat_dir, instruction_set */
+ return create_oat_dir(arg[0], arg[1]);
}
-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);
+static int do_rm_package_dir(char **arg, char reply[REPLY_MAX] __unused)
+{
+ /* oat_dir */
+ return rm_package_dir(arg[0]);
}
struct cmdinfo {
@@ -163,32 +187,34 @@ struct cmdinfo {
struct cmdinfo cmds[] = {
{ "ping", 0, do_ping },
- { "install", 4, do_install },
- { "dexopt", 6, do_dexopt },
+ { "install", 5, do_install },
+ { "dexopt", 9, do_dexopt },
{ "markbootcomplete", 1, do_mark_boot_complete },
{ "movedex", 3, do_move_dex },
{ "rmdex", 2, do_rm_dex },
- { "remove", 2, do_remove },
+ { "remove", 3, do_remove },
{ "rename", 2, do_rename },
- { "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 },
+ { "fixuid", 4, do_fixuid },
+ { "freecache", 2, do_free_cache },
+ { "rmcache", 3, do_rm_cache },
+ { "rmcodecache", 3, do_rm_code_cache },
+ { "getsize", 8, do_get_size },
+ { "rmuserdata", 3, do_rm_user_data },
+ { "mvuserdata", 5, do_mv_user_data },
{ "movefiles", 0, do_movefiles },
- { "linklib", 3, do_linklib },
- { "mkuserdata", 4, do_mk_user_data },
+ { "linklib", 4, do_linklib },
+ { "mkuserdata", 5, do_mk_user_data },
{ "mkuserconfig", 1, do_mk_user_config },
- { "rmuser", 1, do_rm_user },
+ { "rmuser", 2, do_rm_user },
{ "idmap", 3, do_idmap },
- { "restorecondata", 3, do_restorecon_data },
- { "patchoat", 5, do_patchoat },
+ { "restorecondata", 4, do_restorecon_data },
+ { "createoatdir", 2, do_create_oat_dir },
+ { "rmpackagedir", 1, do_rm_package_dir},
};
static int readx(int s, void *_buf, int count)
{
- char *buf = _buf;
+ char *buf = (char *) _buf;
int n = 0, r;
if (count < 0) return -1;
while (n < count) {
@@ -209,7 +235,7 @@ static int readx(int s, void *_buf, int count)
static int writex(int s, const void *_buf, int count)
{
- const char *buf = _buf;
+ const char *buf = (const char *) _buf;
int n = 0, r;
if (count < 0) return -1;
while (n < count) {
@@ -255,7 +281,9 @@ static int execute(int s, char cmd[BUFFER_MAX])
goto done;
}
}
- cmd++;
+ if (*cmd) {
+ cmd++;
+ }
}
for (i = 0; i < sizeof(cmds) / sizeof(cmds[0]); i++) {
@@ -333,10 +361,15 @@ int initialize_globals() {
return -1;
}
+ // Get the android external app directory.
+ if (get_path_from_string(&android_mnt_expand_dir, "/mnt/expand/") < 0) {
+ return -1;
+ }
+
// Take note of the system and vendor directories.
android_system_dirs.count = 4;
- android_system_dirs.dirs = calloc(android_system_dirs.count, sizeof(dir_rec_t));
+ android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t));
if (android_system_dirs.dirs == NULL) {
ALOGE("Couldn't allocate array for dirs; aborting\n");
return -1;
@@ -354,10 +387,10 @@ int initialize_globals() {
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].path = strdup("/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].path = strdup("/oem/app/");
android_system_dirs.dirs[3].len = strlen(android_system_dirs.dirs[3].path);
return 0;
@@ -501,7 +534,7 @@ int initialize_directories() {
version = 2;
}
- if (ensure_media_user_dirs(0) == -1) {
+ if (ensure_media_user_dirs(nullptr, 0) == -1) {
ALOGE("Failed to setup media for user 0");
goto fail;
}
@@ -596,46 +629,6 @@ fail:
return res;
}
-static void drop_privileges() {
- if (prctl(PR_SET_KEEPCAPS, 1) < 0) {
- ALOGE("prctl(PR_SET_KEEPCAPS) failed: %s\n", strerror(errno));
- exit(1);
- }
-
- if (setgid(AID_INSTALL) < 0) {
- ALOGE("setgid() can't drop privileges; exiting.\n");
- exit(1);
- }
-
- if (setuid(AID_INSTALL) < 0) {
- ALOGE("setuid() can't drop privileges; exiting.\n");
- exit(1);
- }
-
- struct __user_cap_header_struct capheader;
- struct __user_cap_data_struct capdata[2];
- memset(&capheader, 0, sizeof(capheader));
- memset(&capdata, 0, sizeof(capdata));
- capheader.version = _LINUX_CAPABILITY_VERSION_3;
- capheader.pid = 0;
-
- capdata[CAP_TO_INDEX(CAP_DAC_OVERRIDE)].permitted |= CAP_TO_MASK(CAP_DAC_OVERRIDE);
- capdata[CAP_TO_INDEX(CAP_CHOWN)].permitted |= CAP_TO_MASK(CAP_CHOWN);
- capdata[CAP_TO_INDEX(CAP_SETUID)].permitted |= CAP_TO_MASK(CAP_SETUID);
- capdata[CAP_TO_INDEX(CAP_SETGID)].permitted |= CAP_TO_MASK(CAP_SETGID);
- capdata[CAP_TO_INDEX(CAP_FOWNER)].permitted |= CAP_TO_MASK(CAP_FOWNER);
-
- capdata[0].effective = capdata[0].permitted;
- capdata[1].effective = capdata[1].permitted;
- capdata[0].inheritable = 0;
- capdata[1].inheritable = 0;
-
- if (capset(&capheader, &capdata[0]) < 0) {
- ALOGE("capset failed: %s\n", strerror(errno));
- exit(1);
- }
-}
-
static int log_callback(int type, const char *fmt, ...) {
va_list ap;
int priority;
@@ -657,13 +650,16 @@ static int log_callback(int type, const char *fmt, ...) {
return 0;
}
-int main(const int argc, const char *argv[]) {
+int main(const int argc __unused, char *argv[]) {
char buf[BUFFER_MAX];
struct sockaddr addr;
socklen_t alen;
- int lsocket, s, count;
+ int lsocket, s;
int selinux_enabled = (is_selinux_enabled() > 0);
+ setenv("ANDROID_LOG_TAGS", "*:v", 1);
+ android::base::InitLogging(argv);
+
ALOGI("installd firing up\n");
union selinux_callback cb;
@@ -685,8 +681,6 @@ int main(const int argc, const char *argv[]) {
exit(1);
}
- drop_privileges();
-
lsocket = android_get_control_socket(SOCKET_PATH);
if (lsocket < 0) {
ALOGE("Failed to get socket from environment: %s\n", strerror(errno));
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index a3a5c16..f31bf4f 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -31,6 +31,8 @@
#include <sys/socket.h>
#include <sys/types.h>
#include <sys/wait.h>
+#include <string>
+#include <vector>
#include <cutils/fs.h>
#include <cutils/sockets.h>
@@ -40,7 +42,7 @@
#include <private/android_filesystem_config.h>
-#if INCLUDE_SYS_MOUNT_FOR_STATFS
+#if defined(__APPLE__)
#include <sys/mount.h>
#else
#include <sys/statfs.h>
@@ -83,6 +85,13 @@
#define PKG_NAME_MAX 128 /* largest allowed package name */
#define PKG_PATH_MAX 256 /* max size of any path we use */
+/* dexopt needed flags matching those in dalvik.system.DexFile */
+#define DEXOPT_DEX2OAT_NEEDED 1
+#define DEXOPT_PATCHOAT_NEEDED 2
+#define DEXOPT_SELF_PATCHOAT_NEEDED 3
+
+#define ARRAY_SIZE(a) (sizeof(a) / sizeof(*(a)))
+
/* data structures */
typedef struct {
@@ -101,6 +110,7 @@ extern dir_rec_t android_app_lib_dir;
extern dir_rec_t android_data_dir;
extern dir_rec_t android_asec_dir;
extern dir_rec_t android_media_dir;
+extern dir_rec_t android_mnt_expand_dir;
extern dir_rec_array_t android_system_dirs;
typedef struct cache_dir_struct {
@@ -132,20 +142,22 @@ typedef struct {
/* util.c */
-int create_pkg_path_in_dir(char path[PKG_PATH_MAX],
- const dir_rec_t* dir,
- const char* pkgname,
- const char* postfix);
+// TODO: rename to create_data_user_package_path
+std::string create_package_data_path(const char* volume_uuid,
+ const char* package_name, userid_t user);
int create_pkg_path(char path[PKG_PATH_MAX],
const char *pkgname,
const char *postfix,
userid_t userid);
-int create_user_path(char path[PKG_PATH_MAX],
- userid_t userid);
+std::string create_data_path(const char* volume_uuid);
+
+std::string create_data_user_path(const char* volume_uuid, userid_t userid);
+
+std::string create_data_media_path(const char* volume_uuid, userid_t userid);
-int create_user_media_path(char path[PKG_PATH_MAX], userid_t userid);
+std::vector<userid_t> get_known_users(const char* volume_uuid);
int create_user_config_path(char path[PKG_PATH_MAX], userid_t userid);
@@ -169,13 +181,13 @@ int copy_dir_files(const char *srcname, const char *dstname, uid_t owner, gid_t
int lookup_media_dir(char basepath[PATH_MAX], const char *dir);
-int64_t data_disk_free();
+int64_t data_disk_free(const std::string& data_path);
cache_t* start_cache_collection();
void add_cache_files(cache_t* cache, const char *basepath, const char *cachedir);
-void clear_cache_files(cache_t* cache, int64_t free_size);
+void clear_cache_files(const std::string& data_path, cache_t* cache, int64_t free_size);
void finish_cache_collection(cache_t* cache);
@@ -191,38 +203,48 @@ int validate_apk_path(const char *path);
int append_and_increment(char** dst, const char* src, size_t* dst_size);
-char *build_string2(char *s1, char *s2);
-char *build_string3(char *s1, char *s2, char *s3);
+char *build_string2(const char *s1, const char *s2);
+char *build_string3(const char *s1, const char *s2, const char *s3);
int ensure_dir(const char* path, mode_t mode, uid_t uid, gid_t gid);
-int ensure_media_user_dirs(userid_t userid);
+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 */
-int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo);
-int uninstall(const char *pkgname, userid_t userid);
+int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const char *seinfo);
+int uninstall(const char *uuid, const char *pkgname, userid_t userid);
int renamepkg(const char *oldpkgname, const char *newpkgname);
-int fix_uid(const char *pkgname, uid_t uid, gid_t gid);
-int delete_user_data(const char *pkgname, userid_t userid);
-int make_user_data(const char *pkgname, uid_t uid, userid_t userid, const char* seinfo);
+int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid);
+int delete_user_data(const char *uuid, const char *pkgname, userid_t userid);
+int make_user_data(const char *uuid, const char *pkgname, uid_t uid,
+ userid_t userid, const char* seinfo);
+int move_user_data(const char* from_uuid, const char *to_uuid,
+ const char *package_name, appid_t appid, const char* seinfo);
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 delete_user(const char *uuid, userid_t userid);
+int delete_cache(const char *uuid, const char *pkgname, userid_t userid);
+int delete_code_cache(const char *uuid, 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);
-int get_size(const char *pkgname, userid_t userid, const char *apkpath, const char *libdirpath,
+int get_size(const char *uuid, const char *pkgname, userid_t userid, const char *apkpath, const char *libdirpath,
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 free_cache(const char *uuid, int64_t free_size);
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);
+ const char *instruction_set, int dexopt_needed, bool vm_safe_mode,
+ bool debuggable, const char* oat_dir);
int mark_boot_complete(const char *instruction_set);
int movefiles();
-int linklib(const char* target, const char* source, int userId);
+int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int userId);
int idmap(const char *target_path, const char *overlay_path, uid_t uid);
-int restorecon_data();
+int restorecon_data(const char *uuid, const char* pkgName, const char* seinfo, uid_t uid);
+int create_oat_dir(const char* oat_dir, const char *instruction_set);
+int rm_package_dir(const char* apk_path);
+int calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
+ const char *instruction_set);
+int move_package_dir(char path[PKG_PATH_MAX], const char *oat_dir, const char *apk_path,
+ const char *instruction_set);
diff --git a/cmds/installd/tests/Android.mk b/cmds/installd/tests/Android.mk
index 4faf3c0..38a9f69 100644
--- a/cmds/installd/tests/Android.mk
+++ b/cmds/installd/tests/Android.mk
@@ -1,21 +1,20 @@
# Build the unit tests for installd
LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
# Build the unit tests.
test_src_files := \
installd_utils_test.cpp
shared_libraries := \
+ libbase \
libutils \
libcutils \
- libstlport
static_libraries := \
libinstalld \
libdiskusage \
- libgtest \
- libgtest_main
c_includes := \
frameworks/native/cmds/installd
@@ -27,5 +26,6 @@ $(foreach file,$(test_src_files), \
$(eval LOCAL_SRC_FILES := $(file)) \
$(eval LOCAL_C_INCLUDES := $(c_includes)) \
$(eval LOCAL_MODULE := $(notdir $(file:%.cpp=%))) \
+ $(eval LOCAL_CLANG := true) \
$(eval include $(BUILD_NATIVE_TEST)) \
)
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 94e4792..4ce559d 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -17,19 +17,18 @@
#include <stdlib.h>
#include <string.h>
-#define LOG_TAG "utils_test"
-#include <utils/Log.h>
-
#include <gtest/gtest.h>
-extern "C" {
#include "installd.h"
-}
+
+#undef LOG_TAG
+#define LOG_TAG "utils_test"
#define TEST_DATA_DIR "/data/"
#define TEST_APP_DIR "/data/app/"
#define TEST_APP_PRIVATE_DIR "/data/app-private/"
#define TEST_ASEC_DIR "/mnt/asec/"
+#define TEST_EXPAND_DIR "/mnt/expand/"
#define TEST_SYSTEM_DIR1 "/system/app/"
#define TEST_SYSTEM_DIR2 "/vendor/app/"
@@ -49,25 +48,28 @@ namespace android {
class UtilsTest : public testing::Test {
protected:
virtual void SetUp() {
- android_app_dir.path = TEST_APP_DIR;
+ android_app_dir.path = (char*) TEST_APP_DIR;
android_app_dir.len = strlen(TEST_APP_DIR);
- android_app_private_dir.path = TEST_APP_PRIVATE_DIR;
+ android_app_private_dir.path = (char*) TEST_APP_PRIVATE_DIR;
android_app_private_dir.len = strlen(TEST_APP_PRIVATE_DIR);
- android_data_dir.path = TEST_DATA_DIR;
+ android_data_dir.path = (char*) TEST_DATA_DIR;
android_data_dir.len = strlen(TEST_DATA_DIR);
- android_asec_dir.path = TEST_ASEC_DIR;
+ android_asec_dir.path = (char*) TEST_ASEC_DIR;
android_asec_dir.len = strlen(TEST_ASEC_DIR);
+ android_mnt_expand_dir.path = (char*) TEST_EXPAND_DIR;
+ android_mnt_expand_dir.len = strlen(TEST_EXPAND_DIR);
+
android_system_dirs.count = 2;
android_system_dirs.dirs = (dir_rec_t*) calloc(android_system_dirs.count, sizeof(dir_rec_t));
- android_system_dirs.dirs[0].path = TEST_SYSTEM_DIR1;
+ android_system_dirs.dirs[0].path = (char*) TEST_SYSTEM_DIR1;
android_system_dirs.dirs[0].len = strlen(TEST_SYSTEM_DIR1);
- android_system_dirs.dirs[1].path = TEST_SYSTEM_DIR2;
+ android_system_dirs.dirs[1].path = (char*) TEST_SYSTEM_DIR2;
android_system_dirs.dirs[1].len = strlen(TEST_SYSTEM_DIR2);
}
@@ -319,6 +321,7 @@ TEST_F(UtilsTest, CreatePkgPath_LongPkgNameSuccess) {
const char *prefix = TEST_DATA_DIR PRIMARY_USER_PREFIX;
size_t offset = strlen(prefix);
+
EXPECT_STREQ(pkgname, path + offset)
<< "Package path should be a really long string of a's";
}
@@ -369,40 +372,6 @@ TEST_F(UtilsTest, CreatePkgPath_SecondaryUser) {
<< "Package path should be in /data/user/";
}
-TEST_F(UtilsTest, CreatePkgPathInDir_ProtectedDir) {
- char path[PKG_PATH_MAX];
-
- dir_rec_t dir;
- dir.path = "/data/app-private/";
- dir.len = strlen(dir.path);
-
- EXPECT_EQ(0, create_pkg_path_in_dir(path, &dir, "com.example.package", ".apk"))
- << "Should successfully create package path.";
-
- EXPECT_STREQ("/data/app-private/com.example.package.apk", path)
- << "Package path should be in /data/app-private/";
-}
-
-TEST_F(UtilsTest, CreatePersonaPath_Primary) {
- char path[PKG_PATH_MAX];
-
- EXPECT_EQ(0, create_user_path(path, 0))
- << "Should successfully build primary user path.";
-
- EXPECT_STREQ("/data/data/", path)
- << "Primary user should have correct path";
-}
-
-TEST_F(UtilsTest, CreatePersonaPath_Secondary) {
- char path[PKG_PATH_MAX];
-
- EXPECT_EQ(0, create_user_path(path, 1))
- << "Should successfully build primary user path.";
-
- EXPECT_STREQ("/data/user/1/", path)
- << "Primary user should have correct path";
-}
-
TEST_F(UtilsTest, CreateMovePath_Primary) {
char path[PKG_PATH_MAX];
@@ -432,7 +401,7 @@ TEST_F(UtilsTest, CopyAndAppend_Normal) {
dir_rec_t dst;
dir_rec_t src;
- src.path = "/data/";
+ src.path = (char*) "/data/";
src.len = strlen(src.path);
EXPECT_EQ(0, copy_and_append(&dst, &src, "app/"))
@@ -480,4 +449,40 @@ TEST_F(UtilsTest, AppendAndIncrement_TooBig) {
<< "String should fail because it's too large to fit";
}
+TEST_F(UtilsTest, CreateDataPath) {
+ EXPECT_EQ("/data", create_data_path(nullptr));
+ EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b",
+ create_data_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b"));
+}
+
+TEST_F(UtilsTest, CreateDataUserPath) {
+ EXPECT_EQ("/data/data", create_data_user_path(nullptr, 0));
+ EXPECT_EQ("/data/user/10", create_data_user_path(nullptr, 10));
+
+ EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/0",
+ create_data_user_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0));
+ EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/10",
+ create_data_user_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10));
+}
+
+TEST_F(UtilsTest, CreateDataMediaPath) {
+ EXPECT_EQ("/data/media/0", create_data_media_path(nullptr, 0));
+ EXPECT_EQ("/data/media/10", create_data_media_path(nullptr, 10));
+
+ EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/media/0",
+ create_data_media_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0));
+ EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/media/10",
+ create_data_media_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10));
+}
+
+TEST_F(UtilsTest, CreatePackageDataPath) {
+ EXPECT_EQ("/data/data/com.example", create_package_data_path(nullptr, "com.example", 0));
+ EXPECT_EQ("/data/user/10/com.example", create_package_data_path(nullptr, "com.example", 10));
+
+ EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/0/com.example",
+ create_package_data_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example", 0));
+ EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/user/10/com.example",
+ create_package_data_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example", 10));
+}
+
}
diff --git a/cmds/installd/utils.c b/cmds/installd/utils.cpp
index e381aef..ba411cd 100644
--- a/cmds/installd/utils.c
+++ b/cmds/installd/utils.cpp
@@ -16,137 +16,119 @@
#include "installd.h"
-#define CACHE_NOISY(x) //x
-
-int create_pkg_path_in_dir(char path[PKG_PATH_MAX],
- const dir_rec_t* dir,
- const char* pkgname,
- const char* postfix)
-{
- const size_t postfix_len = strlen(postfix);
-
- const size_t pkgname_len = strlen(pkgname);
- if (pkgname_len > PKG_NAME_MAX) {
- return -1;
- }
-
- if (is_valid_package_name(pkgname) < 0) {
- return -1;
- }
-
- if ((pkgname_len + dir->len + postfix_len) >= PKG_PATH_MAX) {
- return -1;
- }
-
- char *dst = path;
- size_t dst_size = PKG_PATH_MAX;
+#include <base/stringprintf.h>
+#include <base/logging.h>
- if (append_and_increment(&dst, dir->path, &dst_size) < 0
- || append_and_increment(&dst, pkgname, &dst_size) < 0
- || append_and_increment(&dst, postfix, &dst_size) < 0) {
- ALOGE("Error building APK path");
- return -1;
- }
+#define CACHE_NOISY(x) //x
- return 0;
-}
+using android::base::StringPrintf;
/**
- * Create the package path name for a given package name with a postfix for
- * a certain userid. Returns 0 on success, and -1 on failure.
+ * Check that given string is valid filename, and that it attempts no
+ * parent or child directory traversal.
*/
-int create_pkg_path(char path[PKG_PATH_MAX],
- const char *pkgname,
- const char *postfix,
- userid_t userid)
-{
- size_t userid_len;
- char* userid_prefix;
- if (userid == 0) {
- userid_prefix = PRIMARY_USER_PREFIX;
- userid_len = 0;
+static bool is_valid_filename(const std::string& name) {
+ if (name.empty() || (name == ".") || (name == "..")
+ || (name.find('/') != std::string::npos)) {
+ return false;
} else {
- userid_prefix = SECONDARY_USER_PREFIX;
- userid_len = snprintf(NULL, 0, "%d", userid);
+ return true;
}
+}
- const size_t prefix_len = android_data_dir.len + strlen(userid_prefix)
- + userid_len + 1 /*slash*/;
- char prefix[prefix_len + 1];
+/**
+ * Create the path name where package data should be stored for the given
+ * volume UUID, package name, and user ID. An empty UUID is assumed to be
+ * internal storage.
+ */
+std::string create_package_data_path(const char* volume_uuid,
+ const char* package_name, userid_t user) {
+ CHECK(is_valid_filename(package_name));
+ CHECK(is_valid_package_name(package_name) == 0);
- char *dst = prefix;
- size_t dst_size = sizeof(prefix);
+ return StringPrintf("%s/%s", create_data_user_path(volume_uuid, user).c_str(), package_name);
+}
- if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0
- || append_and_increment(&dst, userid_prefix, &dst_size) < 0) {
- ALOGE("Error building prefix for APK path");
+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) {
+ path[0] = '\0';
return -1;
}
- if (userid != 0) {
- int ret = snprintf(dst, dst_size, "%d/", userid);
- if (ret < 0 || (size_t) ret != userid_len + 1) {
- ALOGW("Error appending UID to APK path");
- return -1;
- }
+ std::string _tmp(create_package_data_path(nullptr, pkgname, userid) + postfix);
+ const char* tmp = _tmp.c_str();
+ if (strlen(tmp) >= PKG_PATH_MAX) {
+ path[0] = '\0';
+ return -1;
+ } else {
+ strcpy(path, tmp);
+ return 0;
}
+}
- dir_rec_t dir;
- dir.path = prefix;
- dir.len = prefix_len;
-
- return create_pkg_path_in_dir(path, &dir, pkgname, postfix);
+std::string create_data_path(const char* volume_uuid) {
+ if (volume_uuid == nullptr) {
+ return "/data";
+ } else {
+ CHECK(is_valid_filename(volume_uuid));
+ return StringPrintf("/mnt/expand/%s", volume_uuid);
+ }
}
/**
* Create the path name for user data for a certain userid.
- * Returns 0 on success, and -1 on failure.
*/
-int create_user_path(char path[PKG_PATH_MAX],
- userid_t userid)
-{
- size_t userid_len;
- char* userid_prefix;
- if (userid == 0) {
- userid_prefix = PRIMARY_USER_PREFIX;
- userid_len = 0;
+std::string create_data_user_path(const char* volume_uuid, userid_t userid) {
+ std::string data(create_data_path(volume_uuid));
+ if (volume_uuid == nullptr) {
+ if (userid == 0) {
+ return StringPrintf("%s/data", data.c_str());
+ } else {
+ return StringPrintf("%s/user/%u", data.c_str(), userid);
+ }
} else {
- userid_prefix = SECONDARY_USER_PREFIX;
- userid_len = snprintf(NULL, 0, "%d/", userid);
+ return StringPrintf("%s/user/%u", data.c_str(), userid);
}
+}
- char *dst = path;
- size_t dst_size = PKG_PATH_MAX;
+/**
+ * Create the path name for media for a certain userid.
+ */
+std::string create_data_media_path(const char* volume_uuid, userid_t userid) {
+ return StringPrintf("%s/media/%u", create_data_path(volume_uuid).c_str(), userid);
+}
- if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0
- || append_and_increment(&dst, userid_prefix, &dst_size) < 0) {
- ALOGE("Error building prefix for user path");
- return -1;
+std::vector<userid_t> get_known_users(const char* volume_uuid) {
+ std::vector<userid_t> users;
+
+ // We always have an owner
+ users.push_back(0);
+
+ std::string path(create_data_path(volume_uuid) + "/" + SECONDARY_USER_PREFIX);
+ DIR* dir = opendir(path.c_str());
+ if (dir == NULL) {
+ // Unable to discover other users, but at least return owner
+ PLOG(ERROR) << "Failed to opendir " << path;
+ return users;
}
- if (userid != 0) {
- if (dst_size < userid_len + 1) {
- ALOGE("Error building user path");
- return -1;
+ struct dirent* ent;
+ while ((ent = readdir(dir))) {
+ if (ent->d_type != DT_DIR) {
+ continue;
}
- int ret = snprintf(dst, dst_size, "%d/", userid);
- if (ret < 0 || (size_t) ret != userid_len) {
- ALOGE("Error appending userid to path");
- return -1;
+
+ char* end;
+ userid_t user = strtol(ent->d_name, &end, 10);
+ if (*end == '\0' && user != 0) {
+ LOG(DEBUG) << "Found valid user " << user;
+ users.push_back(user);
}
}
- return 0;
-}
+ closedir(dir);
-/**
- * Create the path name for media for a certain userid.
- * Returns 0 on success, and -1 on failure.
- */
-int create_user_media_path(char path[PATH_MAX], userid_t userid) {
- if (snprintf(path, PATH_MAX, "%s%d", android_media_dir.path, userid) > PATH_MAX) {
- return -1;
- }
- return 0;
+ return users;
}
/**
@@ -163,7 +145,7 @@ int create_user_config_path(char path[PATH_MAX], userid_t userid) {
int create_move_path(char path[PKG_PATH_MAX],
const char* pkgname,
const char* leaf,
- userid_t userid)
+ userid_t userid __unused)
{
if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1)
>= PKG_PATH_MAX) {
@@ -182,6 +164,10 @@ int is_valid_package_name(const char* pkgname) {
const char *x = pkgname;
int alpha = -1;
+ if (strlen(pkgname) > PKG_NAME_MAX) {
+ return -1;
+ }
+
while (*x) {
if (isalnum(*x) || (*x == '_')) {
/* alphanumeric or underscore are fine */
@@ -239,7 +225,7 @@ static int _delete_dir_contents(DIR *d,
}
if (de->d_type == DT_DIR) {
- int r, subfd;
+ int subfd;
DIR *subdir;
/* always skip "." and ".." */
@@ -472,13 +458,13 @@ int lookup_media_dir(char basepath[PATH_MAX], const char *dir)
return -1;
}
-int64_t data_disk_free()
+int64_t data_disk_free(const std::string& data_path)
{
struct statfs sfs;
- if (statfs(android_data_dir.path, &sfs) == 0) {
+ if (statfs(data_path.c_str(), &sfs) == 0) {
return sfs.f_bavail * sfs.f_bsize;
} else {
- ALOGE("Couldn't statfs %s: %s\n", android_data_dir.path, strerror(errno));
+ PLOG(ERROR) << "Couldn't statfs " << data_path;
return -1;
}
}
@@ -516,7 +502,7 @@ static void* _cache_malloc(cache_t* cache, size_t len)
int8_t* res = cache->curMemBlockAvail;
int8_t* nextPos = res + len;
if (cache->memBlocks == NULL || nextPos > cache->curMemBlockEnd) {
- int8_t* newBlock = malloc(CACHE_BLOCK_SIZE);
+ int8_t* newBlock = (int8_t*) malloc(CACHE_BLOCK_SIZE);
if (newBlock == NULL) {
return NULL;
}
@@ -836,7 +822,7 @@ static int cache_modtime_sort(const void *lhsP, const void *rhsP)
return lhs->modTime < rhs->modTime ? -1 : (lhs->modTime > rhs->modTime ? 1 : 0);
}
-void clear_cache_files(cache_t* cache, int64_t free_size)
+void clear_cache_files(const std::string& data_path, cache_t* cache, int64_t free_size)
{
size_t i;
int skip = 0;
@@ -861,7 +847,7 @@ void clear_cache_files(cache_t* cache, int64_t free_size)
for (i=0; i<cache->numFiles; i++) {
skip++;
if (skip > 10) {
- if (data_disk_free() > free_size) {
+ if (data_disk_free(data_path) > free_size) {
return;
}
skip = 0;
@@ -881,7 +867,7 @@ void clear_cache_files(cache_t* cache, int64_t free_size)
void finish_cache_collection(cache_t* cache)
{
- size_t i;
+ CACHE_NOISY(size_t i;)
CACHE_NOISY(ALOGI("clear_cache_files: %d dirs, %d files\n", cache->numDirs, cache->numFiles));
CACHE_NOISY(
@@ -910,14 +896,14 @@ void finish_cache_collection(cache_t* cache)
* 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) {
+static int validate_path(const dir_rec_t* dir, const char* path, int maxSubdirs) {
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) {
+ if ((--maxSubdirs == 0) && strchr(subdir, '/') != NULL) {
ALOGE("invalid apk path '%s' (subdir?)\n", path);
return -1;
}
@@ -942,7 +928,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)) {
- return validate_path(android_system_dirs.dirs + i, path);
+ return validate_path(android_system_dirs.dirs + i, path, 1);
}
}
@@ -1000,7 +986,7 @@ int get_path_from_string(dir_rec_t* rec, const char* path) {
// Add space for slash and terminating null.
size_t dst_size = path_len + 2;
- rec->path = malloc(dst_size);
+ rec->path = (char*) malloc(dst_size);
if (rec->path == NULL) {
return -1;
}
@@ -1042,6 +1028,7 @@ int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) {
int validate_apk_path(const char *path)
{
const dir_rec_t* dir = NULL;
+ int maxSubdirs = 1;
if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
dir = &android_app_dir;
@@ -1049,11 +1036,14 @@ int validate_apk_path(const char *path)
dir = &android_app_private_dir;
} else if (!strncmp(path, android_asec_dir.path, android_asec_dir.len)) {
dir = &android_asec_dir;
+ } else if (!strncmp(path, android_mnt_expand_dir.path, android_mnt_expand_dir.len)) {
+ dir = &android_mnt_expand_dir;
+ maxSubdirs = 2;
} else {
return -1;
}
- return validate_path(dir, path);
+ return validate_path(dir, path, maxSubdirs);
}
int append_and_increment(char** dst, const char* src, size_t* dst_size) {
@@ -1066,13 +1056,13 @@ int append_and_increment(char** dst, const char* src, size_t* dst_size) {
return 0;
}
-char *build_string2(char *s1, char *s2) {
+char *build_string2(const char *s1, const char *s2) {
if (s1 == NULL || s2 == NULL) return NULL;
int len_s1 = strlen(s1);
int len_s2 = strlen(s2);
int len = len_s1 + len_s2 + 1;
- char *result = malloc(len);
+ char *result = (char *) malloc(len);
if (result == NULL) return NULL;
strcpy(result, s1);
@@ -1081,14 +1071,14 @@ char *build_string2(char *s1, char *s2) {
return result;
}
-char *build_string3(char *s1, char *s2, char *s3) {
+char *build_string3(const char *s1, const char *s2, const char *s3) {
if (s1 == NULL || s2 == NULL || s3 == NULL) return NULL;
int len_s1 = strlen(s1);
int len_s2 = strlen(s2);
int len_s3 = strlen(s3);
int len = len_s1 + len_s2 + len_s3 + 1;
- char *result = malloc(len);
+ char *result = (char *) malloc(len);
if (result == NULL) return NULL;
strcpy(result, s1);
@@ -1099,13 +1089,9 @@ char *build_string3(char *s1, char *s2, char *s3) {
}
/* Ensure that /data/media directories are prepared for given user. */
-int ensure_media_user_dirs(userid_t userid) {
- char media_user_path[PATH_MAX];
- char path[PATH_MAX];
-
- // Ensure /data/media/<userid> exists
- create_user_media_path(media_user_path, userid);
- if (fs_prepare_dir(media_user_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
+int ensure_media_user_dirs(const char* uuid, userid_t userid) {
+ std::string media_user_path(create_data_media_path(uuid, userid));
+ if (fs_prepare_dir(media_user_path.c_str(), 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
return -1;
}
@@ -1114,7 +1100,6 @@ int ensure_media_user_dirs(userid_t userid) {
int ensure_config_user_dirs(userid_t userid) {
char config_user_path[PATH_MAX];
- char path[PATH_MAX];
// writable by system, readable by any app within the same user
const int uid = multiuser_get_uid(userid, AID_SYSTEM);
diff --git a/cmds/servicemanager/bctest.c b/cmds/servicemanager/bctest.c
index e02b45d..fd91633 100644
--- a/cmds/servicemanager/bctest.c
+++ b/cmds/servicemanager/bctest.c
@@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <errno.h>
#include "binder.h"
diff --git a/cmds/servicemanager/binder.c b/cmds/servicemanager/binder.c
index db7632d..6eecee1 100644
--- a/cmds/servicemanager/binder.c
+++ b/cmds/servicemanager/binder.c
@@ -4,6 +4,7 @@
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
@@ -112,7 +113,9 @@ struct binder_state *binder_open(size_t mapsize)
if ((ioctl(bs->fd, BINDER_VERSION, &vers) == -1) ||
(vers.protocol_version != BINDER_CURRENT_PROTOCOL_VERSION)) {
- fprintf(stderr, "binder: driver version differs from user space\n");
+ fprintf(stderr,
+ "binder: kernel driver version (%d) differs from user space version (%d)\n",
+ vers.protocol_version, BINDER_CURRENT_PROTOCOL_VERSION);
goto fail_open;
}
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index f37427a..cacfe14 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -1,10 +1,12 @@
/* Copyright 2008 The Android Open Source Project
*/
-#include <stdio.h>
-#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include <private/android_filesystem_config.h>
@@ -21,8 +23,6 @@
#include <cutils/log.h>
#endif
-uint32_t svcmgr_handle;
-
const char *str8(const uint16_t *x, size_t x_len)
{
static char buf[128];
@@ -169,28 +169,26 @@ uint16_t svcmgr_id[] = {
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;
+ struct svcinfo *si = find_svc(s, len);
- if (!svc_can_find(s, len, spid)) {
- ALOGE("find_service('%s') uid=%d - PERMISSION DENIED\n",
- str8(s, len), uid);
+ if (!si || !si->handle) {
return 0;
}
- si = find_svc(s, len);
- //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,
- // then check the uid to see if it is isolated.
- uid_t appid = uid % AID_USER;
- if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
- return 0;
- }
+
+ if (!si->allow_isolated) {
+ // If this service doesn't allow access from isolated processes,
+ // then check the uid to see if it is isolated.
+ uid_t appid = uid % AID_USER;
+ if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
+ return 0;
}
- return si->handle;
- } else {
+ }
+
+ if (!svc_can_find(s, len, spid)) {
return 0;
}
+
+ return si->handle;
}
int do_add_service(struct binder_state *bs,
@@ -255,10 +253,10 @@ int svcmgr_handler(struct binder_state *bs,
uint32_t strict_policy;
int allow_isolated;
- //ALOGI("target=%x code=%d pid=%d uid=%d\n",
- // txn->target.handle, txn->code, txn->sender_pid, txn->sender_euid);
+ //ALOGI("target=%p code=%d pid=%d uid=%d\n",
+ // (void*) txn->target.ptr, txn->code, txn->sender_pid, txn->sender_euid);
- if (txn->target.handle != svcmgr_handle)
+ if (txn->target.ptr != BINDER_SERVICE_MANAGER)
return -1;
if (txn->code == PING_TRANSACTION)
@@ -382,7 +380,6 @@ int main(int argc, char **argv)
cb.func_log = selinux_log_callback;
selinux_set_callback(SELINUX_CB_LOG, cb);
- svcmgr_handle = BINDER_SERVICE_MANAGER;
binder_loop(bs, svcmgr_handler);
return 0;