summaryrefslogtreecommitdiffstats
path: root/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'cmds')
-rw-r--r--cmds/atrace/atrace.cpp5
-rw-r--r--cmds/bugreport/bugreport.cpp2
-rw-r--r--cmds/dumpstate/dumpstate.c192
-rw-r--r--cmds/dumpstate/dumpstate.h17
-rw-r--r--cmds/dumpstate/utils.c87
-rw-r--r--cmds/installd/commands.cpp307
-rw-r--r--cmds/installd/installd.cpp17
-rw-r--r--cmds/installd/installd.h26
-rw-r--r--cmds/installd/tests/installd_utils_test.cpp24
-rw-r--r--cmds/installd/utils.cpp54
-rw-r--r--cmds/service/service.cpp34
-rw-r--r--cmds/servicemanager/service_manager.c1
12 files changed, 605 insertions, 161 deletions
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 515d761..9def406 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -137,6 +137,9 @@ static const TracingCategory k_categories[] = {
{ REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable" },
{ REQ, "/sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable" },
} },
+ { "regulators", "Voltage and Current Regulators", 0, {
+ { REQ, "/sys/kernel/debug/tracing/events/regulator/enable" },
+ } },
};
/* Command line options */
@@ -897,7 +900,7 @@ int main(int argc, char **argv)
g_traceOverwrite = true;
} else if (!strcmp(long_options[option_index].name, "async_stop")) {
async = true;
- traceStop = false;
+ traceStart = false;
} else if (!strcmp(long_options[option_index].name, "async_dump")) {
async = true;
traceStart = false;
diff --git a/cmds/bugreport/bugreport.cpp b/cmds/bugreport/bugreport.cpp
index b606406..6892b57 100644
--- a/cmds/bugreport/bugreport.cpp
+++ b/cmds/bugreport/bugreport.cpp
@@ -86,6 +86,6 @@ int main() {
} while (bytes_written != 0 && bytes_to_send > 0);
}
- TEMP_FAILURE_RETRY(close(s));
+ close(s);
return 0;
}
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index a33dcf3..ef8db06 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -18,6 +18,7 @@
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
+#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -99,8 +100,170 @@ static void dump_dev_files(const char *title, const char *driverpath, const char
closedir(d);
}
+static bool skip_not_stat(const char *path) {
+ static const char stat[] = "/stat";
+ size_t len = strlen(path);
+ if (path[len - 1] == '/') { /* Directory? */
+ return false;
+ }
+ return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */
+}
+
+static const char mmcblk0[] = "/sys/block/mmcblk0/";
+unsigned long worst_write_perf = 20000; /* in KB/s */
+
+static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
+ unsigned long fields[11], read_perf, write_perf;
+ bool z;
+ char *cp, *buffer = NULL;
+ size_t i = 0;
+ FILE *fp = fdopen(fd, "rb");
+ getline(&buffer, &i, fp);
+ fclose(fp);
+ if (!buffer) {
+ return -errno;
+ }
+ i = strlen(buffer);
+ while ((i > 0) && (buffer[i - 1] == '\n')) {
+ buffer[--i] = '\0';
+ }
+ if (!*buffer) {
+ free(buffer);
+ return 0;
+ }
+ z = true;
+ for (cp = buffer, i = 0; i < (sizeof(fields) / sizeof(fields[0])); ++i) {
+ fields[i] = strtol(cp, &cp, 0);
+ if (fields[i] != 0) {
+ z = false;
+ }
+ }
+ if (z) { /* never accessed */
+ free(buffer);
+ return 0;
+ }
+
+ if (!strncmp(path, mmcblk0, sizeof(mmcblk0) - 1)) {
+ path += sizeof(mmcblk0) - 1;
+ }
+
+ printf("%s: %s\n", path, buffer);
+ free(buffer);
+
+ read_perf = 0;
+ if (fields[3]) {
+ read_perf = 512 * fields[2] / fields[3];
+ }
+ write_perf = 0;
+ if (fields[7]) {
+ write_perf = 512 * fields[6] / fields[7];
+ }
+ printf("%s: read: %luKB/s write: %luKB/s\n", path, read_perf, write_perf);
+ if ((write_perf > 1) && (write_perf < worst_write_perf)) {
+ worst_write_perf = write_perf;
+ }
+ return 0;
+}
+
+/* Copied policy from system/core/logd/LogBuffer.cpp */
+
+#define LOG_BUFFER_SIZE (256 * 1024)
+#define LOG_BUFFER_MIN_SIZE (64 * 1024UL)
+#define LOG_BUFFER_MAX_SIZE (256 * 1024 * 1024UL)
+
+static bool valid_size(unsigned long value) {
+ if ((value < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < value)) {
+ return false;
+ }
+
+ long pages = sysconf(_SC_PHYS_PAGES);
+ if (pages < 1) {
+ return true;
+ }
+
+ long pagesize = sysconf(_SC_PAGESIZE);
+ if (pagesize <= 1) {
+ pagesize = PAGE_SIZE;
+ }
+
+ // maximum memory impact a somewhat arbitrary ~3%
+ pages = (pages + 31) / 32;
+ unsigned long maximum = pages * pagesize;
+
+ if ((maximum < LOG_BUFFER_MIN_SIZE) || (LOG_BUFFER_MAX_SIZE < maximum)) {
+ return true;
+ }
+
+ return value <= maximum;
+}
+
+static unsigned long property_get_size(const char *key) {
+ unsigned long value;
+ char *cp, property[PROPERTY_VALUE_MAX];
+
+ property_get(key, property, "");
+ value = strtoul(property, &cp, 10);
+
+ switch(*cp) {
+ case 'm':
+ case 'M':
+ value *= 1024;
+ /* FALLTHRU */
+ case 'k':
+ case 'K':
+ value *= 1024;
+ /* FALLTHRU */
+ case '\0':
+ break;
+
+ default:
+ value = 0;
+ }
+
+ if (!valid_size(value)) {
+ value = 0;
+ }
+
+ return value;
+}
+
+/* timeout in ms */
+static unsigned long logcat_timeout(char *name) {
+ static const char global_tuneable[] = "persist.logd.size"; // Settings App
+ static const char global_default[] = "ro.logd.size"; // BoardConfig.mk
+ char key[PROP_NAME_MAX];
+ unsigned long property_size, default_size;
+
+ default_size = property_get_size(global_tuneable);
+ if (!default_size) {
+ default_size = property_get_size(global_default);
+ }
+
+ snprintf(key, sizeof(key), "%s.%s", global_tuneable, name);
+ property_size = property_get_size(key);
+
+ if (!property_size) {
+ snprintf(key, sizeof(key), "%s.%s", global_default, name);
+ property_size = property_get_size(key);
+ }
+
+ if (!property_size) {
+ property_size = default_size;
+ }
+
+ if (!property_size) {
+ property_size = LOG_BUFFER_SIZE;
+ }
+
+ /* Engineering margin is ten-fold our guess */
+ return 10 * (property_size + worst_write_perf) / worst_write_perf;
+}
+
+/* End copy from system/core/logd/LogBuffer.cpp */
+
/* dumps the current system state to stdout */
static void dumpstate() {
+ unsigned long timeout;
time_t now = time(NULL);
char build[PROPERTY_VALUE_MAX], fingerprint[PROPERTY_VALUE_MAX];
char radio[PROPERTY_VALUE_MAX], bootloader[PROPERTY_VALUE_MAX];
@@ -133,7 +296,7 @@ static void dumpstate() {
dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
run_command("UPTIME", 10, "uptime", NULL);
- dump_file("MMC PERF", "/sys/block/mmcblk0/stat");
+ dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
dump_file("MEMORY INFO", "/proc/meminfo");
run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL);
run_command("PROCRANK", 20, "procrank", NULL);
@@ -149,7 +312,6 @@ static void dumpstate() {
dump_file("KERNEL WAKE SOURCES", "/d/wakeup_sources");
dump_file("KERNEL CPUFREQ", "/sys/devices/system/cpu/cpu0/cpufreq/stats/time_in_state");
dump_file("KERNEL SYNC", "/d/sync");
- dump_file("KERNEL BLUEDROID", "/d/bluedroid");
run_command("PROCESSES", 10, "ps", "-P", NULL);
run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL);
@@ -169,9 +331,24 @@ static void dumpstate() {
}
// dump_file("EVENT LOG TAGS", "/etc/event-log-tags");
- run_command("SYSTEM LOG", 20, "logcat", "-v", "threadtime", "-d", "*:v", NULL);
- run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL);
- run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL);
+ // calculate timeout
+ timeout = logcat_timeout("main") + logcat_timeout("system") + logcat_timeout("crash");
+ if (timeout < 20000) {
+ timeout = 20000;
+ }
+ run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime", "-d", "*:v", NULL);
+ timeout = logcat_timeout("events");
+ if (timeout < 20000) {
+ timeout = 20000;
+ }
+ run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL);
+ timeout = logcat_timeout("radio");
+ if (timeout < 20000) {
+ timeout = 20000;
+ }
+ run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL);
+
+ run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
/* show the traces we collected in main(), if that was done */
if (dump_traces_path != NULL) {
@@ -242,8 +419,6 @@ static void dumpstate() {
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, "ip", "link", NULL);
@@ -259,6 +434,8 @@ static void dumpstate() {
run_command("ARP CACHE", 10, "ip", "-4", "neigh", "show", NULL);
run_command("IPv6 ND CACHE", 10, "ip", "-6", "neigh", "show", NULL);
+ run_command("NETWORK DIAGNOSTICS", 10, "dumpsys", "connectivity", "--diag", NULL);
+
run_command("IPTABLES", 10, SU_PATH, "root", "iptables", "-L", "-nvx", NULL);
run_command("IP6TABLES", 10, SU_PATH, "root", "ip6tables", "-L", "-nvx", NULL);
run_command("IPTABLE NAT", 10, SU_PATH, "root", "iptables", "-t", "nat", "-L", "-nvx", NULL);
@@ -362,6 +539,7 @@ static void dumpstate() {
run_command("CHECKIN NETSTATS", 30, "dumpsys", "netstats", "--checkin", NULL);
run_command("CHECKIN PROCSTATS", 30, "dumpsys", "procstats", "-c", NULL);
run_command("CHECKIN USAGESTATS", 30, "dumpsys", "usagestats", "-c", NULL);
+ run_command("CHECKIN PACKAGE", 30, "dumpsys", "package", "--checkin", NULL);
printf("========================================================\n");
printf("== Running Application Activities\n");
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index d17a677..c5d3044 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -26,7 +26,6 @@
typedef void (for_each_pid_func)(int, const char *);
typedef void (for_each_tid_func)(int, int, const char *);
-typedef void (for_each_userid_func)(int);
/* prints the contents of a file */
int dump_file(const char *title, const char *path);
@@ -36,6 +35,16 @@ int dump_file(const char *title, const char *path);
*/
int dump_file_from_fd(const char *title, const char *path, int fd);
+/* calls skip to gate calling dump_from_fd recursively
+ * in the specified directory. dump_from_fd defaults to
+ * dump_file_from_fd above when set to NULL. skip defaults
+ * to false when set to NULL. dump_from_fd will always be
+ * called with title NULL.
+ */
+int dump_files(const char *title, const char *dir,
+ bool (*skip)(const char *path),
+ int (*dump_from_fd)(const char *title, const char *path, int fd));
+
/* forks a command and waits for it to finish -- terminate args with NULL */
int run_command(const char *title, int timeout_seconds, const char *command, ...);
@@ -57,9 +66,6 @@ void for_each_pid(for_each_pid_func func, const char *header);
/* for each thread in the system, run the specified function */
void for_each_tid(for_each_tid_func func, const char *header);
-/* for each user id in the system, run the specified function */
-void for_each_userid(for_each_userid_func func, const char *header);
-
/* Displays a blocked processes in-kernel wait channel */
void show_wchan(int pid, int tid, const char *name);
@@ -69,9 +75,6 @@ void do_showmap(int pid, const char *name);
/* Gets the dmesg output for the kernel */
void do_dmesg();
-/* Dumps settings for a given user id */
-void do_dump_settings(int userid);
-
/* Prints the contents of all the routing tables, both IPv4 and IPv6. */
void dump_route_tables();
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index cf14c8b..d679787 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -206,22 +206,6 @@ out_close:
return;
}
-void do_dump_settings(int userid) {
- char title[255];
- char dbpath[255];
- char sql[255];
- sprintf(title, "SYSTEM SETTINGS (user %d)", userid);
- if (userid == 0) {
- strcpy(dbpath, "/data/data/com.android.providers.settings/databases/settings.db");
- strcpy(sql, "pragma user_version; select * from system; select * from secure; select * from global;");
- } else {
- sprintf(dbpath, "/data/system/users/%d/settings.db", userid);
- strcpy(sql, "pragma user_version; select * from system; select * from secure;");
- }
- run_command(title, 20, SU_PATH, "root", "sqlite3", dbpath, sql, NULL);
- return;
-}
-
void do_dmesg() {
printf("------ KERNEL LOG (dmesg) ------\n");
/* Get size of kernel buffer */
@@ -306,7 +290,7 @@ static int _dump_file_from_fd(const char *title, const char *path, int fd) {
}
}
}
- TEMP_FAILURE_RETRY(close(fd));
+ close(fd);
if (!newline) printf("\n");
if (title) printf("\n");
@@ -326,6 +310,75 @@ int dump_file(const char *title, const char *path) {
return _dump_file_from_fd(title, path, fd);
}
+/* calls skip to gate calling dump_from_fd recursively
+ * in the specified directory. dump_from_fd defaults to
+ * dump_file_from_fd above when set to NULL. skip defaults
+ * to false when set to NULL. dump_from_fd will always be
+ * called with title NULL.
+ */
+int dump_files(const char *title, const char *dir,
+ bool (*skip)(const char *path),
+ int (*dump_from_fd)(const char *title, const char *path, int fd)) {
+ DIR *dirp;
+ struct dirent *d;
+ char *newpath = NULL;
+ char *slash = "/";
+ int fd, retval = 0;
+
+ if (title) {
+ printf("------ %s (%s) ------\n", title, dir);
+ }
+
+ if (dir[strlen(dir) - 1] == '/') {
+ ++slash;
+ }
+ dirp = opendir(dir);
+ if (dirp == NULL) {
+ retval = -errno;
+ fprintf(stderr, "%s: %s\n", dir, strerror(errno));
+ return retval;
+ }
+
+ if (!dump_from_fd) {
+ dump_from_fd = dump_file_from_fd;
+ }
+ for (; ((d = readdir(dirp))); free(newpath), newpath = NULL) {
+ if ((d->d_name[0] == '.')
+ && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
+ || (d->d_name[1] == '\0'))) {
+ continue;
+ }
+ asprintf(&newpath, "%s%s%s%s", dir, slash, d->d_name,
+ (d->d_type == DT_DIR) ? "/" : "");
+ if (!newpath) {
+ retval = -errno;
+ continue;
+ }
+ if (skip && (*skip)(newpath)) {
+ continue;
+ }
+ if (d->d_type == DT_DIR) {
+ int ret = dump_files(NULL, newpath, skip, dump_from_fd);
+ if (ret < 0) {
+ retval = ret;
+ }
+ continue;
+ }
+ fd = TEMP_FAILURE_RETRY(open(newpath, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
+ if (fd < 0) {
+ retval = fd;
+ printf("*** %s: %s\n", newpath, strerror(errno));
+ continue;
+ }
+ (*dump_from_fd)(NULL, newpath, fd);
+ }
+ closedir(dirp);
+ if (title) {
+ printf("\n");
+ }
+ return retval;
+}
+
/* 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.
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index de6fd96..7090b36 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -50,7 +50,7 @@ int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const c
return -1;
}
- std::string _pkgdir(create_package_data_path(uuid, pkgname, 0));
+ std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname));
const char* pkgdir = _pkgdir.c_str();
if (mkdir(pkgdir, 0751) < 0) {
@@ -80,7 +80,7 @@ int install(const char *uuid, const char *pkgname, uid_t uid, gid_t gid, const c
int uninstall(const char *uuid, const char *pkgname, userid_t userid)
{
- std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
+ std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname));
const char* pkgdir = _pkgdir.c_str();
remove_profile_file(pkgname);
@@ -115,7 +115,7 @@ int fix_uid(const char *uuid, const char *pkgname, uid_t uid, gid_t gid)
return -1;
}
- std::string _pkgdir(create_package_data_path(uuid, pkgname, 0));
+ std::string _pkgdir(create_data_user_package_path(uuid, 0, pkgname));
const char* pkgdir = _pkgdir.c_str();
if (stat(pkgdir, &s) < 0) return -1;
@@ -141,7 +141,7 @@ 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)
{
- std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
+ std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname));
const char* pkgdir = _pkgdir.c_str();
return delete_dir_contents(pkgdir, 0, NULL);
@@ -149,7 +149,7 @@ 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)
{
- std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
+ std::string _pkgdir(create_data_user_package_path(uuid, userid, pkgname));
const char* pkgdir = _pkgdir.c_str();
if (mkdir(pkgdir, 0751) < 0) {
@@ -177,15 +177,48 @@ int make_user_data(const char *uuid, const char *pkgname, uid_t uid, userid_t us
return 0;
}
-int move_user_data(const char *from_uuid, const char *to_uuid,
- const char *package_name, appid_t appid, const char* seinfo) {
+int copy_complete_app(const char *from_uuid, const char *to_uuid,
+ const char *package_name, const char *data_app_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
+ // Copy app
+ {
+ std::string from(create_data_app_package_path(from_uuid, data_app_name));
+ std::string to(create_data_app_package_path(to_uuid, data_app_name));
+ std::string to_parent(create_data_app_path(to_uuid));
+
+ 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_parent.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 (selinux_android_restorecon(to.c_str(), SELINUX_ANDROID_RESTORECON_RECURSE) != 0) {
+ LOG(ERROR) << "Failed to restorecon " << to;
+ goto fail;
+ }
+ }
+
+ // Copy 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));
+ std::string from(create_data_user_package_path(from_uuid, user, package_name));
+ std::string to(create_data_user_package_path(to_uuid, user, package_name));
+ std::string to_parent(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) {
@@ -213,7 +246,7 @@ int move_user_data(const char *from_uuid, const char *to_uuid,
(char*) "-P", /* Do not follow symlinks [default] */
(char*) "-d", /* don't dereference symlinks */
(char*) from.c_str(),
- (char*) to_user.c_str()
+ (char*) to_parent.c_str()
};
LOG(DEBUG) << "Copying " << from << " to " << to;
@@ -224,26 +257,28 @@ int move_user_data(const char *from_uuid, const char *to_uuid,
<< ": 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;
- }
+ if (restorecon_data(to_uuid, package_name, seinfo, multiuser_get_uid(0, appid)) != 0) {
+ LOG(ERROR) << "Failed to restorecon";
+ goto fail;
}
+
+ // We let the framework scan the new location and persist that before
+ // deleting the data in the old location; this ordering ensures that
+ // we can recover from things like battery pulls.
return 0;
fail:
// Nuke everything we might have already copied
+ {
+ std::string to(create_data_app_package_path(to_uuid, data_app_name));
+ if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+ LOG(WARNING) << "Failed to rollback " << to;
+ }
+ }
for (auto user : users) {
- std::string to(create_package_data_path(to_uuid, package_name, user));
+ std::string to(create_data_user_package_path(to_uuid, user, package_name));
if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
LOG(WARNING) << "Failed to rollback " << to;
}
@@ -289,7 +324,7 @@ int delete_user(const char *uuid, userid_t userid)
int delete_cache(const char *uuid, const char *pkgname, userid_t userid)
{
std::string _cachedir(
- create_package_data_path(uuid, pkgname, userid) + CACHE_DIR_POSTFIX);
+ create_data_user_package_path(uuid, userid, pkgname) + CACHE_DIR_POSTFIX);
const char* cachedir = _cachedir.c_str();
/* delete contents, not the directory, no exceptions */
@@ -299,7 +334,7 @@ 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)
{
std::string _codecachedir(
- create_package_data_path(uuid, pkgname, userid) + CACHE_DIR_POSTFIX);
+ create_data_user_package_path(uuid, userid, pkgname) + CODE_CACHE_DIR_POSTFIX);
const char* codecachedir = _codecachedir.c_str();
struct stat s;
@@ -454,7 +489,7 @@ int rm_dex(const char *path, const char *instruction_set)
}
}
-int get_size(const char *uuid, const char *pkgname, userid_t userid, const char *apkpath,
+int get_size(const char *uuid, const char *pkgname, int 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)
@@ -470,30 +505,38 @@ int get_size(const char *uuid, const char *pkgname, userid_t userid, const char
int64_t cachesize = 0;
int64_t asecsize = 0;
- /* count the source apk as code -- but only if it's not
- * on the /system partition and its not on the sdcard.
- */
+ /* count the source apk as code -- but only if it's not
+ * on the /system partition and its not on the sdcard. */
if (validate_system_app_path(apkpath) &&
strncmp(apkpath, android_asec_dir.path, android_asec_dir.len) != 0) {
if (stat(apkpath, &s) == 0) {
codesize += stat_size(&s);
+ if (S_ISDIR(s.st_mode)) {
+ d = opendir(apkpath);
+ if (d != NULL) {
+ dfd = dirfd(d);
+ codesize += calculate_dir_size(dfd);
+ closedir(d);
+ }
+ }
}
}
- /* count the forward locked apk as code if it is given
- */
+
+ /* count the forward locked apk as code if it is given */
if (fwdlock_apkpath != NULL && fwdlock_apkpath[0] != '!') {
if (stat(fwdlock_apkpath, &s) == 0) {
codesize += stat_size(&s);
}
}
- /* count the cached dexfile as code */
+
+ /* count the cached dexfile as code */
if (!create_cache_path(path, apkpath, instruction_set)) {
if (stat(path, &s) == 0) {
codesize += stat_size(&s);
}
}
- /* add in size of any libraries */
+ /* add in size of any libraries */
if (libdirpath != NULL && libdirpath[0] != '!') {
d = opendir(libdirpath);
if (d != NULL) {
@@ -503,68 +546,76 @@ int get_size(const char *uuid, const char *pkgname, userid_t userid, const char
}
}
- /* compute asec size if it is given
- */
+ /* compute asec size if it is given */
if (asecpath != NULL && asecpath[0] != '!') {
if (stat(asecpath, &s) == 0) {
asecsize += stat_size(&s);
}
}
- std::string _pkgdir(create_package_data_path(uuid, pkgname, userid));
- const char* pkgdir = _pkgdir.c_str();
-
- d = opendir(pkgdir);
- if (d == NULL) {
- goto done;
+ std::vector<userid_t> users;
+ if (userid == -1) {
+ users = get_known_users(uuid);
+ } else {
+ users.push_back(userid);
}
- dfd = dirfd(d);
- /* most stuff in the pkgdir is data, except for the "cache"
- * directory and below, which is cache, and the "lib" directory
- * and below, which is code...
- */
- while ((de = readdir(d))) {
- const char *name = de->d_name;
+ for (auto user : users) {
+ std::string _pkgdir(create_data_user_package_path(uuid, user, pkgname));
+ const char* pkgdir = _pkgdir.c_str();
- if (de->d_type == DT_DIR) {
- int subfd;
- int64_t statsize = 0;
- int64_t dirsize = 0;
- /* always skip "." and ".." */
- if (name[0] == '.') {
- if (name[1] == 0) continue;
- if ((name[1] == '.') && (name[2] == 0)) continue;
- }
- if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
- statsize = stat_size(&s);
- }
- subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
- if (subfd >= 0) {
- dirsize = calculate_dir_size(subfd);
- }
- if(!strcmp(name,"lib")) {
- codesize += dirsize + statsize;
- } else if(!strcmp(name,"cache")) {
- cachesize += dirsize + statsize;
+ d = opendir(pkgdir);
+ if (d == NULL) {
+ PLOG(WARNING) << "Failed to open " << pkgdir;
+ continue;
+ }
+ dfd = dirfd(d);
+
+ /* most stuff in the pkgdir is data, except for the "cache"
+ * directory and below, which is cache, and the "lib" directory
+ * and below, which is code...
+ */
+ while ((de = readdir(d))) {
+ const char *name = de->d_name;
+
+ if (de->d_type == DT_DIR) {
+ int subfd;
+ int64_t statsize = 0;
+ int64_t dirsize = 0;
+ /* always skip "." and ".." */
+ if (name[0] == '.') {
+ if (name[1] == 0) continue;
+ if ((name[1] == '.') && (name[2] == 0)) continue;
+ }
+ if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
+ statsize = stat_size(&s);
+ }
+ subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
+ if (subfd >= 0) {
+ dirsize = calculate_dir_size(subfd);
+ }
+ if(!strcmp(name,"lib")) {
+ codesize += dirsize + statsize;
+ } else if(!strcmp(name,"cache")) {
+ cachesize += dirsize + statsize;
+ } else {
+ datasize += dirsize + statsize;
+ }
+ } else if (de->d_type == DT_LNK && !strcmp(name,"lib")) {
+ // This is the symbolic link to the application's library
+ // code. We'll count this as code instead of data, since
+ // it is not something that the app creates.
+ if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
+ codesize += stat_size(&s);
+ }
} else {
- datasize += dirsize + statsize;
- }
- } else if (de->d_type == DT_LNK && !strcmp(name,"lib")) {
- // This is the symbolic link to the application's library
- // code. We'll count this as code instead of data, since
- // it is not something that the app creates.
- if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
- codesize += stat_size(&s);
- }
- } else {
- if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
- datasize += stat_size(&s);
+ if (fstatat(dfd, name, &s, AT_SYMLINK_NOFOLLOW) == 0) {
+ datasize += stat_size(&s);
+ }
}
}
+ closedir(d);
}
- closedir(d);
-done:
*_codesize = codesize;
*_datasize = datasize;
*_cachesize = cachesize;
@@ -684,6 +735,15 @@ static void run_patchoat(int input_fd, int oat_fd, const char* input_file_name,
ALOGE("execv(%s) failed: %s\n", PATCHOAT_BIN, strerror(errno));
}
+static bool check_boolean_property(const char* property_name, bool default_value = false) {
+ char tmp_property_value[PROPERTY_VALUE_MAX];
+ bool have_property = property_get(property_name, tmp_property_value, nullptr) > 0;
+ if (!have_property) {
+ return default_value;
+ }
+ return strcmp(tmp_property_value, "true") == 0;
+}
+
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 debuggable)
@@ -744,9 +804,8 @@ 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;
+ bool use_jit = check_boolean_property("debug.usejit");
+ bool generate_debug_info = check_boolean_property("debug.generate-debug-info");
static const char* DEX2OAT_BIN = "/system/bin/dex2oat";
@@ -839,6 +898,7 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
+ (have_dex2oat_threads_flag ? 1 : 0)
+ (have_dex2oat_swap_fd ? 1 : 0)
+ (have_dex2oat_relocation_skip_flag ? 2 : 0)
+ + (generate_debug_info ? 1 : 0)
+ (debuggable ? 1 : 0)
+ dex2oat_flags_count];
int i = 0;
@@ -877,6 +937,9 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
if (have_dex2oat_swap_fd) {
argv[i++] = dex2oat_swap_fd;
}
+ if (generate_debug_info) {
+ argv[i++] = "--generate-debug-info";
+ }
if (debuggable) {
argv[i++] = "--debuggable";
}
@@ -921,20 +984,49 @@ static int wait_child(pid_t pid)
}
/*
- * Whether dexopt should use a swap file when compiling an APK. If kAlwaysProvideSwapFile, do this
- * on all devices (dex2oat will make a more informed decision itself, anyways). Otherwise, only do
- * this on a low-mem device.
+ * Whether dexopt should use a swap file when compiling an APK.
+ *
+ * If kAlwaysProvideSwapFile, do this on all devices (dex2oat will make a more informed decision
+ * itself, anyways).
+ *
+ * Otherwise, read "dalvik.vm.dex2oat-swap". If the property exists, return whether it is "true".
+ *
+ * Otherwise, return true if this is a low-mem device.
+ *
+ * Otherwise, return default value.
*/
-static bool kAlwaysProvideSwapFile = true;
+static bool kAlwaysProvideSwapFile = false;
+static bool kDefaultProvideSwapFile = true;
static bool ShouldUseSwapFileForDexopt() {
if (kAlwaysProvideSwapFile) {
return true;
}
- char low_mem_buf[PROPERTY_VALUE_MAX];
- property_get("ro.config.low_ram", low_mem_buf, "");
- return (strcmp(low_mem_buf, "true") == 0);
+ // Check the "override" property. If it exists, return value == "true".
+ char dex2oat_prop_buf[PROPERTY_VALUE_MAX];
+ if (property_get("dalvik.vm.dex2oat-swap", dex2oat_prop_buf, "") > 0) {
+ if (strcmp(dex2oat_prop_buf, "true") == 0) {
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ // Shortcut for default value. This is an implementation optimization for the process sketched
+ // above. If the default value is true, we can avoid to check whether this is a low-mem device,
+ // as low-mem is never returning false. The compiler will optimize this away if it can.
+ if (kDefaultProvideSwapFile) {
+ return true;
+ }
+
+ bool is_low_mem = check_boolean_property("ro.config.low_ram");
+ if (is_low_mem) {
+ return true;
+ }
+
+ // Default value must be false here.
+ return kDefaultProvideSwapFile;
}
/*
@@ -1448,7 +1540,7 @@ int linklib(const char* uuid, const char* pkgname, const char* asecLibDir, int u
struct stat s, libStat;
int rc = 0;
- std::string _pkgdir(create_package_data_path(uuid, pkgname, userId));
+ std::string _pkgdir(create_data_user_package_path(uuid, userId, pkgname));
std::string _libsymlink(_pkgdir + PKG_LIB_POSTFIX);
const char* pkgdir = _pkgdir.c_str();
@@ -1639,7 +1731,7 @@ int restorecon_data(const char* uuid, const char* pkgName,
// Special case for owner on internal storage
if (uuid == nullptr) {
- std::string path(create_package_data_path(nullptr, pkgName, 0));
+ std::string path(create_data_user_package_path(nullptr, 0, pkgName));
if (selinux_android_restorecon_pkgdir(path.c_str(), seinfo, uid, flags) < 0) {
PLOG(ERROR) << "restorecon failed for " << path;
@@ -1717,6 +1809,31 @@ int rm_package_dir(const char* apk_path)
return delete_dir_contents(apk_path, 1 /* also_delete_dir */ , NULL /* exclusion_predicate */);
}
+int link_file(const char* relative_path, const char* from_base, const char* to_base) {
+ char from_path[PKG_PATH_MAX];
+ char to_path[PKG_PATH_MAX];
+ snprintf(from_path, PKG_PATH_MAX, "%s/%s", from_base, relative_path);
+ snprintf(to_path, PKG_PATH_MAX, "%s/%s", to_base, relative_path);
+
+ if (validate_apk_path_subdirs(from_path)) {
+ ALOGE("invalid app data sub-path '%s' (bad prefix)\n", from_path);
+ return -1;
+ }
+
+ if (validate_apk_path_subdirs(to_path)) {
+ ALOGE("invalid app data sub-path '%s' (bad prefix)\n", to_path);
+ return -1;
+ }
+
+ const int ret = link(from_path, to_path);
+ if (ret < 0) {
+ ALOGE("link(%s, %s) failed : %s", from_path, to_path, strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
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;
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 3a86181..13e3168 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -124,10 +124,10 @@ static int do_rm_user_data(char **arg, char reply[REPLY_MAX] __unused)
return delete_user_data(parse_null(arg[0]), arg[1], atoi(arg[2])); /* uuid, pkgname, userid */
}
-static int do_mv_user_data(char **arg, char reply[REPLY_MAX] __unused)
+static int do_cp_complete_app(char **arg, char reply[REPLY_MAX] __unused)
{
- // 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]);
+ // from_uuid, to_uuid, package_name, data_app_name, appid, seinfo
+ return copy_complete_app(parse_null(arg[0]), parse_null(arg[1]), arg[2], arg[3], atoi(arg[4]), arg[5]);
}
static int do_mk_user_data(char **arg, char reply[REPLY_MAX] __unused)
@@ -179,6 +179,12 @@ static int do_rm_package_dir(char **arg, char reply[REPLY_MAX] __unused)
return rm_package_dir(arg[0]);
}
+static int do_link_file(char **arg, char reply[REPLY_MAX] __unused)
+{
+ /* relative_path, from_base, to_base */
+ return link_file(arg[0], arg[1], arg[2]);
+}
+
struct cmdinfo {
const char *name;
unsigned numargs;
@@ -200,7 +206,7 @@ struct cmdinfo cmds[] = {
{ "rmcodecache", 3, do_rm_code_cache },
{ "getsize", 8, do_get_size },
{ "rmuserdata", 3, do_rm_user_data },
- { "mvuserdata", 5, do_mv_user_data },
+ { "cpcompleteapp", 6, do_cp_complete_app },
{ "movefiles", 0, do_movefiles },
{ "linklib", 4, do_linklib },
{ "mkuserdata", 5, do_mk_user_data },
@@ -209,7 +215,8 @@ struct cmdinfo cmds[] = {
{ "idmap", 3, do_idmap },
{ "restorecondata", 4, do_restorecon_data },
{ "createoatdir", 2, do_create_oat_dir },
- { "rmpackagedir", 1, do_rm_package_dir},
+ { "rmpackagedir", 1, do_rm_package_dir },
+ { "linkfile", 3, do_link_file }
};
static int readx(int s, void *_buf, int count)
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index f31bf4f..7ec5793 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -142,10 +142,6 @@ typedef struct {
/* util.c */
-// 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,
@@ -153,8 +149,15 @@ int create_pkg_path(char path[PKG_PATH_MAX],
std::string create_data_path(const char* volume_uuid);
+std::string create_data_app_path(const char* volume_uuid);
+
+std::string create_data_app_package_path(const char* volume_uuid, const char* package_name);
+
std::string create_data_user_path(const char* volume_uuid, userid_t userid);
+std::string create_data_user_package_path(const char* volume_uuid,
+ userid_t user, const char* package_name);
+
std::string create_data_media_path(const char* volume_uuid, userid_t userid);
std::vector<userid_t> get_known_users(const char* volume_uuid);
@@ -200,6 +203,7 @@ int get_path_from_string(dir_rec_t* rec, const char* path);
int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix);
int validate_apk_path(const char *path);
+int validate_apk_path_subdirs(const char *path);
int append_and_increment(char** dst, const char* src, size_t* dst_size);
@@ -221,8 +225,9 @@ 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 copy_complete_app(const char* from_uuid, const char *to_uuid,
+ const char *package_name, const char *data_app_name, appid_t appid,
+ const char* seinfo);
int make_user_config(userid_t userid);
int delete_user(const char *uuid, userid_t userid);
int delete_cache(const char *uuid, const char *pkgname, userid_t userid);
@@ -230,9 +235,11 @@ 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 *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 get_size(const char *uuid, const char *pkgname, int 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(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, int dexopt_needed, bool vm_safe_mode,
@@ -248,3 +255,4 @@ int calculate_oat_file_path(char path[PKG_PATH_MAX], const char *oat_dir, const
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);
+int link_file(const char *relative_path, const char *from_base, const char *to_base);
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 4ce559d..5e397f9 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -455,6 +455,13 @@ TEST_F(UtilsTest, CreateDataPath) {
create_data_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b"));
}
+TEST_F(UtilsTest, CreateDataAppPath) {
+ EXPECT_EQ("/data/app", create_data_app_path(nullptr));
+
+ EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/app",
+ create_data_app_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));
@@ -475,14 +482,21 @@ TEST_F(UtilsTest, CreateDataMediaPath) {
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));
+TEST_F(UtilsTest, CreateDataAppPackagePath) {
+ EXPECT_EQ("/data/app/com.example", create_data_app_package_path(nullptr, "com.example"));
+
+ EXPECT_EQ("/mnt/expand/57f8f4bc-abf4-655f-bf67-946fc0f9f25b/app/com.example",
+ create_data_app_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", "com.example"));
+}
+
+TEST_F(UtilsTest, CreateDataUserPackagePath) {
+ EXPECT_EQ("/data/data/com.example", create_data_user_package_path(nullptr, 0, "com.example"));
+ EXPECT_EQ("/data/user/10/com.example", create_data_user_package_path(nullptr, 10, "com.example"));
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));
+ create_data_user_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 0, "com.example"));
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));
+ create_data_user_package_path("57f8f4bc-abf4-655f-bf67-946fc0f9f25b", 10, "com.example"));
}
}
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index ba411cd..7db3fb9 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -37,16 +37,31 @@ static bool is_valid_filename(const std::string& name) {
}
/**
+ * Create the path name where package app contents should be stored for
+ * the given volume UUID and package name. An empty UUID is assumed to
+ * be internal storage.
+ */
+std::string create_data_app_package_path(const char* volume_uuid,
+ const char* package_name) {
+ CHECK(is_valid_filename(package_name));
+ CHECK(is_valid_package_name(package_name) == 0);
+
+ return StringPrintf("%s/%s",
+ create_data_app_path(volume_uuid).c_str(), package_name);
+}
+
+/**
* 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) {
+std::string create_data_user_package_path(const char* volume_uuid,
+ userid_t user, const char* package_name) {
CHECK(is_valid_filename(package_name));
CHECK(is_valid_package_name(package_name) == 0);
- return StringPrintf("%s/%s", create_data_user_path(volume_uuid, user).c_str(), package_name);
+ return StringPrintf("%s/%s",
+ create_data_user_path(volume_uuid, user).c_str(), package_name);
}
int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
@@ -56,7 +71,7 @@ int create_pkg_path(char path[PKG_PATH_MAX], const char *pkgname,
return -1;
}
- std::string _tmp(create_package_data_path(nullptr, pkgname, userid) + postfix);
+ std::string _tmp(create_data_user_package_path(nullptr, userid, pkgname) + postfix);
const char* tmp = _tmp.c_str();
if (strlen(tmp) >= PKG_PATH_MAX) {
path[0] = '\0';
@@ -77,6 +92,13 @@ std::string create_data_path(const char* volume_uuid) {
}
/**
+ * Create the path name for app data.
+ */
+std::string create_data_app_path(const char* volume_uuid) {
+ return StringPrintf("%s/app", create_data_path(volume_uuid).c_str());
+}
+
+/**
* Create the path name for user data for a certain userid.
*/
std::string create_data_user_path(const char* volume_uuid, userid_t userid) {
@@ -1021,15 +1043,13 @@ int copy_and_append(dir_rec_t* dst, const dir_rec_t* src, const char* suffix) {
}
/**
- * Check whether path points to a valid path for an APK file. Only one level of
- * subdirectory names is allowed. Returns -1 when an invalid path is encountered
- * and 0 when a valid path is encountered.
+ * Check whether path points to a valid path for an APK file. The path must
+ * begin with a whitelisted prefix path and must be no deeper than |maxSubdirs| within
+ * that path. Returns -1 when an invalid path is encountered and 0 when a valid path
+ * is encountered.
*/
-int validate_apk_path(const char *path)
-{
+static int validate_apk_path_internal(const char *path, int maxSubdirs) {
const dir_rec_t* dir = NULL;
- int maxSubdirs = 1;
-
if (!strncmp(path, android_app_dir.path, android_app_dir.len)) {
dir = &android_app_dir;
} else if (!strncmp(path, android_app_private_dir.path, android_app_private_dir.len)) {
@@ -1038,7 +1058,9 @@ int validate_apk_path(const char *path)
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;
+ if (maxSubdirs < 2) {
+ maxSubdirs = 2;
+ }
} else {
return -1;
}
@@ -1046,6 +1068,14 @@ int validate_apk_path(const char *path)
return validate_path(dir, path, maxSubdirs);
}
+int validate_apk_path(const char* path) {
+ return validate_apk_path_internal(path, 1 /* maxSubdirs */);
+}
+
+int validate_apk_path_subdirs(const char* path) {
+ return validate_apk_path_internal(path, 3 /* maxSubdirs */);
+}
+
int append_and_increment(char** dst, const char* src, size_t* dst_size) {
ssize_t ret = strlcpy(*dst, src, *dst_size);
if (ret < 0 || (size_t) ret >= *dst_size) {
diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp
index 97fc47c..428b87c 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -146,6 +146,15 @@ int main(int argc, char* const argv[])
break;
}
data.writeInt32(atoi(argv[optind++]));
+ } else if (strcmp(argv[optind], "i64") == 0) {
+ optind++;
+ if (optind >= argc) {
+ aerr << "service: no integer supplied for 'i64'" << endl;
+ wantsUsage = true;
+ result = 10;
+ break;
+ }
+ data.writeInt64(atoll(argv[optind++]));
} else if (strcmp(argv[optind], "s16") == 0) {
optind++;
if (optind >= argc) {
@@ -155,6 +164,24 @@ int main(int argc, char* const argv[])
break;
}
data.writeString16(String16(argv[optind++]));
+ } else if (strcmp(argv[optind], "f") == 0) {
+ optind++;
+ if (optind >= argc) {
+ aerr << "service: no number supplied for 'f'" << endl;
+ wantsUsage = true;
+ result = 10;
+ break;
+ }
+ data.writeFloat(atof(argv[optind++]));
+ } else if (strcmp(argv[optind], "d") == 0) {
+ optind++;
+ if (optind >= argc) {
+ aerr << "service: no number supplied for 'd'" << endl;
+ wantsUsage = true;
+ result = 10;
+ break;
+ }
+ data.writeDouble(atof(argv[optind++]));
} else if (strcmp(argv[optind], "null") == 0) {
optind++;
data.writeStrongBinder(NULL);
@@ -272,9 +299,12 @@ int main(int argc, char* const argv[])
aout << "Usage: service [-h|-?]\n"
" service list\n"
" service check SERVICE\n"
- " service call SERVICE CODE [i32 INT | s16 STR] ...\n"
+ " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR ] ...\n"
"Options:\n"
- " i32: Write the integer INT into the send parcel.\n"
+ " i32: Write the 32-bit integer N into the send parcel.\n"
+ " i64: Write the 64-bit integer N into the send parcel.\n"
+ " f: Write the 32-bit single-precision number N into the send parcel.\n"
+ " d: Write the 64-bit double-precision number N into the send parcel.\n"
" s16: Write the UTF-16 string STR into the send parcel.\n";
// " intent: Write and Intent int the send parcel. ARGS can be\n"
// " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n";
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index cacfe14..7fa9a39 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -361,6 +361,7 @@ int main(int argc, char **argv)
selinux_enabled = is_selinux_enabled();
sehandle = selinux_android_service_context_handle();
+ selinux_status_open(true);
if (selinux_enabled > 0) {
if (sehandle == NULL) {