diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c index 79bda74e84c34..1e8555be91b10 100644 --- a/cmds/installd/commands.c +++ b/cmds/installd/commands.c @@ -78,6 +78,30 @@ int uninstall(const char *pkgname, int encrypted_fs_flag) return delete_dir_contents(pkgdir, 1, 0); } +int renamepkg(const char *oldpkgname, const char *newpkgname, int encrypted_fs_flag) +{ + char oldpkgdir[PKG_PATH_MAX]; + char newpkgdir[PKG_PATH_MAX]; + + if (encrypted_fs_flag == USE_UNENCRYPTED_FS) { + if (create_pkg_path(oldpkgdir, PKG_DIR_PREFIX, oldpkgname, PKG_DIR_POSTFIX)) + return -1; + if (create_pkg_path(newpkgdir, PKG_DIR_PREFIX, newpkgname, PKG_DIR_POSTFIX)) + return -1; + } else { + if (create_pkg_path(oldpkgdir, PKG_SEC_DIR_PREFIX, oldpkgname, PKG_DIR_POSTFIX)) + return -1; + if (create_pkg_path(newpkgdir, PKG_SEC_DIR_PREFIX, newpkgname, PKG_DIR_POSTFIX)) + return -1; + } + + if (rename(oldpkgdir, newpkgdir) < 0) { + LOGE("cannot rename dir '%s' to '%s': %s\n", oldpkgdir, newpkgdir, strerror(errno)); + return -errno; + } + return 0; +} + int delete_user_data(const char *pkgname, int encrypted_fs_flag) { char pkgdir[PKG_PATH_MAX]; @@ -636,3 +660,203 @@ fail: } return -1; } + +int create_move_path(char path[PKG_PATH_MAX], + const char* prefix, + const char* pkgname, + const char* leaf) +{ + if ((strlen(prefix) + strlen(pkgname) + strlen(leaf) + 1) >= PKG_PATH_MAX) { + return -1; + } + + sprintf(path, "%s%s/%s", prefix, pkgname, leaf); + return 0; +} + +void mkinnerdirs(char* path, int basepos, mode_t mode, int uid, int gid) +{ + while (path[basepos] != 0) { + if (path[basepos] == '/') { + path[basepos] = 0; + LOGI("Making directory: %s\n", path); + if (mkdir(path, mode) == 0) { + chown(path, uid, gid); + } + path[basepos] = '/'; + basepos++; + } + basepos++; + } +} + +int movefiles() +{ + DIR *d; + int dfd, subfd; + struct dirent *de; + struct stat s; + char buf[PKG_PATH_MAX+1]; + int bufp, bufe, bufi, readlen; + + char srcpkg[PKG_NAME_MAX]; + char dstpkg[PKG_NAME_MAX]; + char srcpath[PKG_PATH_MAX]; + char dstpath[PKG_PATH_MAX]; + int dstuid, dstgid; + int hasspace; + + d = opendir(UPDATE_COMMANDS_DIR_PREFIX); + if (d == NULL) { + goto done; + } + dfd = dirfd(d); + + /* Iterate through all files in the directory, executing the + * file movements requested there-in. + */ + while ((de = readdir(d))) { + const char *name = de->d_name; + + if (de->d_type == DT_DIR) { + continue; + } else { + subfd = openat(dfd, name, O_RDONLY); + if (subfd < 0) { + LOGW("Unable to open update commands at %s%s\n", + UPDATE_COMMANDS_DIR_PREFIX, name); + continue; + } + + bufp = 0; + bufe = 0; + buf[PKG_PATH_MAX] = 0; + srcpkg[0] = dstpkg[0] = 0; + while (1) { + bufi = bufp; + while (bufi < bufe && buf[bufi] != '\n') { + bufi++; + } + if (bufi < bufe) { + buf[bufi] = 0; + LOGV("Processing line: %s\n", buf+bufp); + hasspace = 0; + while (bufp < bufi && isspace(buf[bufp])) { + hasspace = 1; + bufp++; + } + if (buf[bufp] == '#' || bufp == bufi) { + // skip comments and empty lines. + } else if (hasspace) { + if (dstpkg[0] == 0) { + LOGW("Path before package line in %s%s: %s\n", + UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp); + } else if (srcpkg[0] == 0) { + // Skip -- source package no longer exists. + } else { + LOGV("Move file: %s (from %s to %s)\n", buf+bufp, srcpkg, dstpkg); + if (!create_move_path(srcpath, PKG_DIR_PREFIX, srcpkg, buf+bufp) && + !create_move_path(dstpath, PKG_DIR_PREFIX, dstpkg, buf+bufp)) { + LOGI("Renaming %s to %s (uid %d)\n", srcpath, dstpath, dstuid); + mkinnerdirs(dstpath, strlen(dstpath)-(bufi-bufp), + S_IRWXU|S_IRWXG|S_IXOTH, dstuid, dstgid); + if (rename(srcpath, dstpath) >= 0) { + if (chown(dstpath, dstuid, dstgid) < 0) { + LOGE("cannot chown %s: %s\n", dstpath, strerror(errno)); + unlink(dstpath); + } + } else { + LOGW("Unable to rename %s to %s: %s\n", + srcpath, dstpath, strerror(errno)); + } + } + } + } else { + char* div = strchr(buf+bufp, ':'); + if (div == NULL) { + LOGW("Bad package spec in %s%s; no ':' sep: %s\n", + UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp); + } else { + *div = 0; + div++; + if (strlen(buf+bufp) < PKG_NAME_MAX) { + strcpy(dstpkg, buf+bufp); + } else { + srcpkg[0] = dstpkg[0] = 0; + LOGW("Package name too long in %s%s: %s\n", + UPDATE_COMMANDS_DIR_PREFIX, name, buf+bufp); + } + if (strlen(div) < PKG_NAME_MAX) { + strcpy(srcpkg, div); + } else { + srcpkg[0] = dstpkg[0] = 0; + LOGW("Package name too long in %s%s: %s\n", + UPDATE_COMMANDS_DIR_PREFIX, name, div); + } + if (srcpkg[0] != 0) { + if (!create_pkg_path(srcpath, PKG_DIR_PREFIX, srcpkg, + PKG_DIR_POSTFIX)) { + if (lstat(srcpath, &s) < 0) { + // Package no longer exists -- skip. + srcpkg[0] = 0; + } + } else { + srcpkg[0] = 0; + LOGW("Can't create path %s in %s%s\n", + div, UPDATE_COMMANDS_DIR_PREFIX, name); + } + if (srcpkg[0] != 0) { + if (!create_pkg_path(dstpath, PKG_DIR_PREFIX, dstpkg, + PKG_DIR_POSTFIX)) { + if (lstat(dstpath, &s) == 0) { + dstuid = s.st_uid; + dstgid = s.st_gid; + } else { + srcpkg[0] = 0; + LOGW("Can't stat path %s in %s%s: %s\n", + dstpath, UPDATE_COMMANDS_DIR_PREFIX, + name, strerror(errno)); + } + } else { + srcpkg[0] = 0; + LOGW("Can't create path %s in %s%s\n", + div, UPDATE_COMMANDS_DIR_PREFIX, name); + } + } + LOGV("Transfering from %s to %s: uid=%d\n", + srcpkg, dstpkg, dstuid); + } + } + } + bufp = bufi+1; + } else { + if (bufp == 0) { + if (bufp < bufe) { + LOGW("Line too long in %s%s, skipping: %s\n", + UPDATE_COMMANDS_DIR_PREFIX, name, buf); + } + } else if (bufp < bufe) { + memcpy(buf, buf+bufp, bufe-bufp); + bufe -= bufp; + bufp = 0; + } + readlen = read(subfd, buf+bufe, PKG_PATH_MAX-bufe); + if (readlen < 0) { + LOGW("Failure reading update commands in %s%s: %s\n", + UPDATE_COMMANDS_DIR_PREFIX, name, strerror(errno)); + break; + } else if (readlen == 0) { + break; + } + bufe += readlen; + buf[bufe] = 0; + LOGV("Read buf: %s\n", buf); + } + } + close(subfd); + } + } + closedir(d); +done: + return 0; +} diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c index 5bc6c86f14c98..882c493b59719 100644 --- a/cmds/installd/installd.c +++ b/cmds/installd/installd.c @@ -53,6 +53,11 @@ static int do_remove(char **arg, char reply[REPLY_MAX]) return uninstall(arg[0], atoi(arg[1])); /* pkgname */ } +static int do_rename(char **arg, char reply[REPLY_MAX]) +{ + return renamepkg(arg[0], arg[1], atoi(arg[2])); /* oldpkgname, newpkgname */ +} + static int do_free_cache(char **arg, char reply[REPLY_MAX]) /* TODO int:free_size */ { return free_cache(atoi(arg[0])); /* free_size */ @@ -87,6 +92,11 @@ static int do_rm_user_data(char **arg, char reply[REPLY_MAX]) return delete_user_data(arg[0], atoi(arg[1])); /* pkgname */ } +static int do_movefiles(char **arg, char reply[REPLY_MAX]) +{ + return movefiles(); +} + struct cmdinfo { const char *name; unsigned numargs; @@ -100,11 +110,13 @@ struct cmdinfo cmds[] = { { "movedex", 2, do_move_dex }, { "rmdex", 1, do_rm_dex }, { "remove", 2, do_remove }, + { "rename", 3, do_rename }, { "freecache", 1, do_free_cache }, { "rmcache", 2, do_rm_cache }, { "protect", 2, do_protect }, { "getsize", 4, do_get_size }, { "rmuserdata", 2, do_rm_user_data }, + { "movefiles", 0, do_movefiles }, }; static int readx(int s, void *_buf, int count) diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h index 35a173ea860d0..92ae310d1a3f9 100644 --- a/cmds/installd/installd.h +++ b/cmds/installd/installd.h @@ -73,6 +73,7 @@ #define DALVIK_CACHE_PREFIX "/data/dalvik-cache/" #define DALVIK_CACHE_POSTFIX "/classes.dex" +#define UPDATE_COMMANDS_DIR_PREFIX "/system/etc/updatecmds/" #define PKG_NAME_MAX 128 /* largest allowed package name */ #define PKG_PATH_MAX 256 /* max size of any path we use */ @@ -97,6 +98,7 @@ int delete_dir_contents_fd(int dfd, const char *name); int install(const char *pkgname, int encrypted_fs_flag, uid_t uid, gid_t gid); int uninstall(const char *pkgname, int encrypted_fs_flag); +int renamepkg(const char *oldpkgname, const char *newpkgname, int encrypted_fs_flag); int delete_user_data(const char *pkgname, int encrypted_fs_flag); int delete_cache(const char *pkgname, int encrypted_fs_flag); int move_dex(const char *src, const char *dst); @@ -106,3 +108,4 @@ int get_size(const char *pkgname, const char *apkpath, const char *fwdlock_apkpa int *codesize, int *datasize, int *cachesize, int encrypted_fs_flag); int free_cache(int free_size); int dexopt(const char *apk_path, uid_t uid, int is_public); +int movefiles(); diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java index bbde0a6035bad..bac55cc01582f 100644 --- a/core/java/android/content/pm/PackageParser.java +++ b/core/java/android/content/pm/PackageParser.java @@ -953,6 +953,39 @@ public class PackageParser { return null; } + } else if (tagName.equals("original-package")) { + sa = res.obtainAttributes(attrs, + com.android.internal.R.styleable.AndroidManifestOriginalPackage); + + String name = sa.getNonResourceString( + com.android.internal.R.styleable.AndroidManifestOriginalPackage_name); + + sa.recycle(); + + if (name != null && (flags&PARSE_IS_SYSTEM) != 0) { + pkg.mOriginalPackage = name; + } + + XmlUtils.skipCurrentTag(parser); + + } else if (tagName.equals("adopt-permissions")) { + sa = res.obtainAttributes(attrs, + com.android.internal.R.styleable.AndroidManifestOriginalPackage); + + String name = sa.getNonResourceString( + com.android.internal.R.styleable.AndroidManifestOriginalPackage_name); + + sa.recycle(); + + if (name != null && (flags&PARSE_IS_SYSTEM) != 0) { + if (pkg.mAdoptPermissions == null) { + pkg.mAdoptPermissions = new ArrayList(); + } + pkg.mAdoptPermissions.add(name); + } + + XmlUtils.skipCurrentTag(parser); + } else if (tagName.equals("eat-comment")) { // Just skip this tag XmlUtils.skipCurrentTag(parser); @@ -2528,6 +2561,9 @@ public class PackageParser { public ArrayList usesOptionalLibraries = null; public String[] usesLibraryFiles = null; + public String mOriginalPackage = null; + public ArrayList mAdoptPermissions = null; + // We store the application meta-data independently to avoid multiple unwanted references public Bundle mAppMetaData = null; diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml index 7728c501a6a6b..54781e3c520df 100644 --- a/core/res/res/values/attrs_manifest.xml +++ b/core/res/res/values/attrs_manifest.xml @@ -923,6 +923,19 @@ + + + + +