diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c index a167be06c..0e3ea4249 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.c @@ -1,16 +1,16 @@ /* ** Copyright 2008, The Android Open Source Project ** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at ** -** http://www.apache.org/licenses/LICENSE-2.0 +** http://www.apache.org/licenses/LICENSE-2.0 ** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and ** limitations under the License. */ @@ -115,6 +115,8 @@ int uninstall(const char *pkgname, userid_t userid) if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid)) return -1; + remove_profile_file(pkgname); + /* delete contents AND directory, no exceptions */ return delete_dir_contents(pkgdir, 1, NULL); } @@ -557,9 +559,9 @@ int create_cache_path(char path[PKG_PATH_MAX], const char *src) return -1; } - dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) + + dstlen = srclen + strlen(DALVIK_CACHE_PREFIX) + strlen(DALVIK_CACHE_POSTFIX) + 1; - + if (dstlen > PKG_PATH_MAX) { return -1; } @@ -568,7 +570,7 @@ int create_cache_path(char path[PKG_PATH_MAX], const char *src) DALVIK_CACHE_PREFIX, src + 1, /* skip the leading / */ DALVIK_CACHE_POSTFIX); - + for(tmp = path + strlen(DALVIK_CACHE_PREFIX); *tmp; tmp++) { if (*tmp == '/') { *tmp = '@'; @@ -601,7 +603,7 @@ static void run_dexopt(int zip_fd, int odex_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) + const char* output_file_name, const char *pkgname) { char dex2oat_flags[PROPERTY_VALUE_MAX]; property_get("dalvik.vm.dex2oat-flags", dex2oat_flags, ""); @@ -613,17 +615,25 @@ static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name, char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX]; char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN]; char oat_location_arg[strlen("--oat-name=") + PKG_PATH_MAX]; + char profile_file[strlen("--profile-file=") + PKG_PATH_MAX]; sprintf(zip_fd_arg, "--zip-fd=%d", zip_fd); sprintf(zip_location_arg, "--zip-location=%s", input_file_name); sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd); sprintf(oat_location_arg, "--oat-location=%s", output_file_name); + if (strcmp(pkgname, "*") != 0) { + snprintf(profile_file, sizeof(profile_file), "--profile-file=%s/%s", + DALVIK_CACHE_PREFIX "profiles", pkgname); + } else { + strcpy(profile_file, "--no-profile-file"); + } ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name); execl(DEX2OAT_BIN, DEX2OAT_BIN, zip_fd_arg, zip_location_arg, oat_fd_arg, oat_location_arg, strlen(dex2oat_flags) > 0 ? dex2oat_flags : NULL, + profile_file, (char*) NULL); ALOGE("execl(%s) failed: %s\n", DEX2OAT_BIN, strerror(errno)); } @@ -654,7 +664,8 @@ static int wait_child(pid_t pid) } } -int dexopt(const char *apk_path, uid_t uid, int is_public) +int dexopt(const char *apk_path, uid_t uid, int is_public, + const char *pkgname) { struct utimbuf ut; struct stat apk_stat, dex_stat; @@ -708,6 +719,12 @@ int dexopt(const char *apk_path, uid_t uid, int is_public) goto fail; } + // Create profile file if there is a package name present. + if (strcmp(pkgname, "*") != 0) { + create_profile_file(pkgname, uid); + } + + ALOGV("DexInv: --- BEGIN '%s' ---\n", apk_path); pid_t pid; @@ -740,7 +757,7 @@ int dexopt(const char *apk_path, uid_t uid, int is_public) if (strncmp(persist_sys_dalvik_vm_lib, "libdvm", 6) == 0) { run_dexopt(zip_fd, out_fd, apk_path, out_path); } else if (strncmp(persist_sys_dalvik_vm_lib, "libart", 6) == 0) { - run_dex2oat(zip_fd, out_fd, apk_path, out_path); + run_dex2oat(zip_fd, out_fd, apk_path, out_path, pkgname); } else { exit(69); /* Unexpected persist.sys.dalvik.vm.lib value */ } @@ -804,12 +821,12 @@ int movefileordir(char* srcpath, char* dstpath, int dstbasepos, int srcend = strlen(srcpath); int dstend = strlen(dstpath); - + if (lstat(srcpath, statbuf) < 0) { ALOGW("Unable to stat %s: %s\n", srcpath, strerror(errno)); return 1; } - + if ((statbuf->st_mode&S_IFDIR) == 0) { mkinnerdirs(dstpath, dstbasepos, S_IRWXU|S_IRWXG|S_IXOTH, dstuid, dstgid, statbuf); @@ -835,7 +852,7 @@ int movefileordir(char* srcpath, char* dstpath, int dstbasepos, } res = 0; - + while ((de = readdir(d))) { const char *name = de->d_name; /* always skip "." and ".." */ @@ -843,32 +860,32 @@ int movefileordir(char* srcpath, char* dstpath, int dstbasepos, if (name[1] == 0) continue; if ((name[1] == '.') && (name[2] == 0)) continue; } - + if ((srcend+strlen(name)) >= (PKG_PATH_MAX-2)) { ALOGW("Source path too long; skipping: %s/%s\n", srcpath, name); continue; } - + if ((dstend+strlen(name)) >= (PKG_PATH_MAX-2)) { ALOGW("Destination path too long; skipping: %s/%s\n", dstpath, name); continue; } - + srcpath[srcend] = dstpath[dstend] = '/'; strcpy(srcpath+srcend+1, name); strcpy(dstpath+dstend+1, name); - + if (movefileordir(srcpath, dstpath, dstbasepos, dstuid, dstgid, statbuf) != 0) { res = 1; } - + // Note: we will be leaving empty directories behind in srcpath, // but that is okay, the package manager will be erasing all of the // data associated with .apks that disappear. - + srcpath[srcend] = dstpath[dstend] = 0; } - + closedir(d); return res; } @@ -910,7 +927,7 @@ int movefiles() UPDATE_COMMANDS_DIR_PREFIX, name); continue; } - + bufp = 0; bufe = 0; buf[PKG_PATH_MAX] = 0; diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c index 549aaabbb..b4df3a3ba 100644 --- a/cmds/installd/installd.c +++ b/cmds/installd/installd.c @@ -38,8 +38,8 @@ static int do_install(char **arg, char reply[REPLY_MAX]) static int do_dexopt(char **arg, char reply[REPLY_MAX]) { - /* apk_path, uid, is_public */ - return dexopt(arg[0], atoi(arg[1]), atoi(arg[2])); + /* apk_path, uid, is_public, pkgname */ + return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3]); } static int do_move_dex(char **arg, char reply[REPLY_MAX]) @@ -138,7 +138,7 @@ struct cmdinfo { struct cmdinfo cmds[] = { { "ping", 0, do_ping }, { "install", 4, do_install }, - { "dexopt", 3, do_dexopt }, + { "dexopt", 4, do_dexopt }, { "movedex", 2, do_move_dex }, { "rmdex", 1, do_rm_dex }, { "remove", 2, do_remove }, diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h index cab5cb7ee..b45803185 100644 --- a/cmds/installd/installd.h +++ b/cmds/installd/installd.h @@ -189,6 +189,8 @@ char *build_string3(char *s1, char *s2, 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 create_profile_file(const char *pkgname, gid_t gid); +void remove_profile_file(const char *pkgname); /* commands.c */ @@ -207,7 +209,7 @@ int get_size(const char *pkgname, userid_t userid, const char *apkpath, const ch const char *fwdlock_apkpath, const char *asecpath, int64_t *codesize, int64_t *datasize, int64_t *cachesize, int64_t *asecsize); int free_cache(int64_t free_size); -int dexopt(const char *apk_path, uid_t uid, int is_public); +int dexopt(const char *apk_path, uid_t uid, int is_public, const char *pkgName); int movefiles(); int linklib(const char* target, const char* source, int userId); int idmap(const char *target_path, const char *overlay_path, uid_t uid); diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c index ef634c64d..0642330e8 100644 --- a/cmds/installd/utils.c +++ b/cmds/installd/utils.c @@ -1,16 +1,16 @@ /* ** Copyright 2008, The Android Open Source Project ** -** Licensed under the Apache License, Version 2.0 (the "License"); -** you may not use this file except in compliance with the License. -** You may obtain a copy of the License at +** Licensed under the Apache License, Version 2.0 (the "License"); +** you may not use this file except in compliance with the License. +** You may obtain a copy of the License at ** -** http://www.apache.org/licenses/LICENSE-2.0 +** http://www.apache.org/licenses/LICENSE-2.0 ** -** Unless required by applicable law or agreed to in writing, software -** distributed under the License is distributed on an "AS IS" BASIS, -** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -** See the License for the specific language governing permissions and +** Unless required by applicable law or agreed to in writing, software +** distributed under the License is distributed on an "AS IS" BASIS, +** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +** See the License for the specific language governing permissions and ** limitations under the License. */ @@ -1005,3 +1005,59 @@ int ensure_media_user_dirs(userid_t userid) { return 0; } + +int create_profile_file(const char *pkgname, gid_t gid) { + const char *profile_dir = DALVIK_CACHE_PREFIX "profiles"; + struct stat profileStat; + char profile_file[PKG_PATH_MAX]; + + // If we don't have a profile directory under dalvik-cache we need to create one. + if (stat(profile_dir, &profileStat) < 0) { + // Create the profile directory under dalvik-cache. + if (mkdir(profile_dir, 0711) < 0) { + ALOGE("cannot make profile dir '%s': %s\n", profile_dir, strerror(errno)); + return -1; + } + + // Make the profile directory write-only for group and other. Owner can rwx it. + if (chmod(profile_dir, 0711) < 0) { + ALOGE("cannot chown profile dir '%s': %s\n", profile_dir, strerror(errno)); + unlink(profile_dir); + return -1; + } + } + + snprintf(profile_file, sizeof(profile_file), "%s/%s", profile_dir, pkgname); + + // The 'system' user needs to be able to read the profile to determine if dex2oat + // needs to be run. This is done in dalvik.system.DexFile.isDexOptNeededInternal(). So + // we make it world readable. Not a problem since the dalvik cache is world + // readable anyway. + + int fd = open(profile_file, O_WRONLY | O_CREAT | O_EXCL | O_NOFOLLOW, 0664); + + // Open will fail if the file already exists. We want to ignore that. + if (fd >= 0) { + if (fchown(fd, -1, gid) < 0) { + ALOGE("cannot chown profile file '%s': %s\n", profile_file, strerror(errno)); + close(fd); + unlink(profile_file); + return -1; + } + + if (fchmod(fd, 0664) < 0) { + ALOGE("cannot chmod profile file '%s': %s\n", profile_file, strerror(errno)); + close(fd); + unlink(profile_file); + return -1; + } + close(fd); + } + return 0; +} + +void remove_profile_file(const char *pkgname) { + char profile_file[PKG_PATH_MAX]; + snprintf(profile_file, sizeof(profile_file), "%s/%s", DALVIK_CACHE_PREFIX "profiles", pkgname); + unlink(profile_file); +}