Merge "Implement system data migration support."
This commit is contained in:
committed by
Android (Google) Code Review
commit
fa6bc84e01
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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<String>();
|
||||
}
|
||||
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<String> usesOptionalLibraries = null;
|
||||
public String[] usesLibraryFiles = null;
|
||||
|
||||
public String mOriginalPackage = null;
|
||||
public ArrayList<String> mAdoptPermissions = null;
|
||||
|
||||
// We store the application meta-data independently to avoid multiple unwanted references
|
||||
public Bundle mAppMetaData = null;
|
||||
|
||||
|
||||
@@ -923,6 +923,19 @@
|
||||
<attr name="name" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- Private tag to declare the original package name that this package is
|
||||
based on. Only used for packages installed in the system image. If
|
||||
given, and different than the actual package name, and the given
|
||||
original package was previously installed on the device but the new
|
||||
one was not, then the data for the old one will be renamed to be
|
||||
for the new package.
|
||||
|
||||
<p>This appears as a child tag of the root
|
||||
{@link #AndroidManifest manifest} tag. -->
|
||||
<declare-styleable name="AndroidManifestOriginalPackage" parent="AndroidManifest">
|
||||
<attr name="name" />
|
||||
</declare-styleable>
|
||||
|
||||
<!-- The <code>provider</code> tag declares a
|
||||
{@link android.content.ContentProvider} class that is available
|
||||
as part of the package's application components, supplying structured
|
||||
|
||||
@@ -222,6 +222,21 @@ class Installer {
|
||||
return execute(builder.toString());
|
||||
}
|
||||
|
||||
public int rename(String oldname, String newname, boolean useEncryptedFilesystem) {
|
||||
StringBuilder builder = new StringBuilder("rename");
|
||||
builder.append(' ');
|
||||
builder.append(oldname);
|
||||
builder.append(' ');
|
||||
builder.append(newname);
|
||||
builder.append(' ');
|
||||
if (useEncryptedFilesystem) {
|
||||
builder.append('1');
|
||||
} else {
|
||||
builder.append('0');
|
||||
}
|
||||
return execute(builder.toString());
|
||||
}
|
||||
|
||||
public int deleteCacheFiles(String name, boolean useEncryptedFilesystem) {
|
||||
StringBuilder builder = new StringBuilder("rmcache");
|
||||
builder.append(' ');
|
||||
@@ -308,4 +323,8 @@ class Installer {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public int moveFiles() {
|
||||
return execute("movefiles");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,11 +96,13 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.Date;
|
||||
import java.util.Enumeration;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
@@ -117,6 +119,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
private static final String TAG = "PackageManager";
|
||||
private static final boolean DEBUG_SETTINGS = false;
|
||||
private static final boolean DEBUG_PREFERRED = false;
|
||||
private static final boolean DEBUG_UPGRADE = false;
|
||||
|
||||
private static final boolean MULTIPLE_APPLICATION_UIDS = true;
|
||||
private static final int RADIO_UID = Process.PHONE_UID;
|
||||
@@ -221,7 +224,6 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
|
||||
final Settings mSettings;
|
||||
boolean mRestoredSettings;
|
||||
boolean mReportedUidError;
|
||||
|
||||
// Group-ids that are given to all packages as read from etc/permissions/*.xml.
|
||||
int[] mGlobalGids;
|
||||
@@ -271,6 +273,10 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
final HashMap<String, PackageParser.PermissionGroup> mPermissionGroups =
|
||||
new HashMap<String, PackageParser.PermissionGroup>();
|
||||
|
||||
// Packages whose data we have transfered into another package, thus
|
||||
// should no longer exist.
|
||||
final HashSet<String> mTransferedPackages = new HashSet<String>();
|
||||
|
||||
// Broadcast actions that are only available to the system.
|
||||
final HashSet<String> mProtectedBroadcasts = new HashSet<String>();
|
||||
|
||||
@@ -661,16 +667,43 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
// Find base frameworks (resource packages without code).
|
||||
mFrameworkInstallObserver = new AppDirObserver(
|
||||
mFrameworkDir.getPath(), OBSERVER_EVENTS, true);
|
||||
mFrameworkInstallObserver.startWatching();
|
||||
scanDirLI(mFrameworkDir, PackageParser.PARSE_IS_SYSTEM,
|
||||
scanMode | SCAN_NO_DEX);
|
||||
|
||||
// Collect all system packages.
|
||||
mSystemAppDir = new File(Environment.getRootDirectory(), "app");
|
||||
mSystemInstallObserver = new AppDirObserver(
|
||||
mSystemAppDir.getPath(), OBSERVER_EVENTS, true);
|
||||
mSystemInstallObserver.startWatching();
|
||||
scanDirLI(mSystemAppDir, PackageParser.PARSE_IS_SYSTEM, scanMode);
|
||||
|
||||
if (mInstaller != null) {
|
||||
if (DEBUG_UPGRADE) Log.v(TAG, "Running installd update commands");
|
||||
mInstaller.moveFiles();
|
||||
}
|
||||
|
||||
// Prune any system packages that no longer exist.
|
||||
Iterator<PackageSetting> psit = mSettings.mPackages.values().iterator();
|
||||
while (psit.hasNext()) {
|
||||
PackageSetting ps = psit.next();
|
||||
if ((ps.pkgFlags&ApplicationInfo.FLAG_SYSTEM) != 0
|
||||
&& !mPackages.containsKey(ps.name)) {
|
||||
psit.remove();
|
||||
String msg = "System package " + ps.name
|
||||
+ " no longer exists; wiping its data";
|
||||
reportSettingsProblem(Log.WARN, msg);
|
||||
if (mInstaller != null) {
|
||||
// XXX how to set useEncryptedFSDir for packages that
|
||||
// are not encrypted?
|
||||
mInstaller.remove(ps.name, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mAppInstallDir = new File(dataDir, "app");
|
||||
if (mInstaller == null) {
|
||||
// Make sure these dirs exist, when we are running in
|
||||
@@ -2081,14 +2114,21 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
private static File getSettingsProblemFile() {
|
||||
File dataDir = Environment.getDataDirectory();
|
||||
File systemDir = new File(dataDir, "system");
|
||||
File fname = new File(systemDir, "uiderrors.txt");
|
||||
return fname;
|
||||
}
|
||||
|
||||
private static void reportSettingsProblem(int priority, String msg) {
|
||||
try {
|
||||
File dataDir = Environment.getDataDirectory();
|
||||
File systemDir = new File(dataDir, "system");
|
||||
File fname = new File(systemDir, "uiderrors.txt");
|
||||
File fname = getSettingsProblemFile();
|
||||
FileOutputStream out = new FileOutputStream(fname, true);
|
||||
PrintWriter pw = new PrintWriter(out);
|
||||
pw.println(msg);
|
||||
SimpleDateFormat formatter = new SimpleDateFormat();
|
||||
String dateString = formatter.format(new Date(System.currentTimeMillis()));
|
||||
pw.println(dateString + ": " + msg);
|
||||
pw.close();
|
||||
FileUtils.setPermissions(
|
||||
fname.toString(),
|
||||
@@ -2295,6 +2335,21 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
((pkg.applicationInfo.flags & ApplicationInfo.FLAG_NEVER_ENCRYPT) == 0);
|
||||
}
|
||||
|
||||
private boolean verifyPackageUpdate(PackageSetting oldPkg, PackageParser.Package newPkg) {
|
||||
if ((oldPkg.pkgFlags&ApplicationInfo.FLAG_SYSTEM) == 0) {
|
||||
Log.w(TAG, "Unable to update from " + oldPkg.name
|
||||
+ " to " + newPkg.packageName
|
||||
+ ": old package not in system partition");
|
||||
return false;
|
||||
} else if (mPackages.get(oldPkg.name) != null) {
|
||||
Log.w(TAG, "Unable to update from " + oldPkg.name
|
||||
+ " to " + newPkg.packageName
|
||||
+ ": old package still exists");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private PackageParser.Package scanPackageLI(
|
||||
PackageParser.Package pkg, int parseFlags, int scanMode) {
|
||||
File scanFile = new File(pkg.mScanPath);
|
||||
@@ -2439,22 +2494,67 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we are renaming from an original package name.
|
||||
PackageSetting origPackage = null;
|
||||
if (pkg.mOriginalPackage != null) {
|
||||
// We will only retrieve the setting for it if it already
|
||||
// exists; otherwise we need to make a new one later.
|
||||
origPackage = mSettings.peekPackageLP(pkg.mOriginalPackage);
|
||||
if (origPackage != null) {
|
||||
if (!verifyPackageUpdate(origPackage, pkg)) {
|
||||
origPackage = null;
|
||||
} else if (origPackage.sharedUser != null) {
|
||||
if (!origPackage.sharedUser.name.equals(pkg.mSharedUserId)) {
|
||||
Log.w(TAG, "Unable to migrate data from " + origPackage.name
|
||||
+ " to " + pkg.packageName + ": old uid "
|
||||
+ origPackage.sharedUser.name
|
||||
+ " differs from " + pkg.mSharedUserId);
|
||||
origPackage = null;
|
||||
}
|
||||
} else {
|
||||
if (DEBUG_UPGRADE) Log.v(TAG, "Migrating data from "
|
||||
+ origPackage.name + " to " + pkg.packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mTransferedPackages.contains(pkg.packageName)) {
|
||||
Log.w(TAG, "Package " + pkg.packageName
|
||||
+ " was transferred to another, but its .apk remains");
|
||||
}
|
||||
|
||||
// Just create the setting, don't add it yet. For already existing packages
|
||||
// the PkgSetting exists already and doesn't have to be created.
|
||||
pkgSetting = mSettings.getPackageLP(pkg, suid, destCodeFile,
|
||||
pkgSetting = mSettings.getPackageLP(pkg, origPackage, suid, destCodeFile,
|
||||
destResourceFile, pkg.applicationInfo.flags, true, false);
|
||||
if (pkgSetting == null) {
|
||||
Log.w(TAG, "Creating application package " + pkgName + " failed");
|
||||
mLastScanError = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
|
||||
return null;
|
||||
}
|
||||
if(mSettings.mDisabledSysPackages.get(pkg.packageName) != null) {
|
||||
if (mSettings.mDisabledSysPackages.get(pkg.packageName) != null) {
|
||||
pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP;
|
||||
}
|
||||
|
||||
pkg.applicationInfo.uid = pkgSetting.userId;
|
||||
pkg.mExtras = pkgSetting;
|
||||
|
||||
if (pkg.mAdoptPermissions != null) {
|
||||
// This package wants to adopt ownership of permissions from
|
||||
// another package.
|
||||
for (int i=pkg.mAdoptPermissions.size()-1; i>=0; i--) {
|
||||
String origName = pkg.mAdoptPermissions.get(i);
|
||||
PackageSetting orig = mSettings.peekPackageLP(origName);
|
||||
if (orig != null) {
|
||||
if (verifyPackageUpdate(orig, pkg)) {
|
||||
if (DEBUG_UPGRADE) Log.v(TAG, "Adopting permissions from "
|
||||
+ origName + " to " + pkg.packageName);
|
||||
mSettings.transferPermissions(origName, pkg.packageName);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!verifySignaturesLP(pkgSetting, pkg, parseFlags,
|
||||
(scanMode&SCAN_UPDATE_SIGNATURE) != 0)) {
|
||||
if ((parseFlags&PackageParser.PARSE_IS_SYSTEM) == 0) {
|
||||
@@ -2543,6 +2643,9 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
} else {
|
||||
dataPath = new File(mAppDataDir, pkgName);
|
||||
}
|
||||
|
||||
boolean uidError = false;
|
||||
|
||||
if (dataPath.exists()) {
|
||||
mOutPermissions[1] = 0;
|
||||
FileUtils.getPermissions(dataPath.getPath(), mOutPermissions);
|
||||
@@ -2556,7 +2659,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
// current data so the application will still work.
|
||||
if (mInstaller != null) {
|
||||
int ret = mInstaller.remove(pkgName, useEncryptedFSDir);
|
||||
if(ret >= 0) {
|
||||
if (ret >= 0) {
|
||||
// Old data gone!
|
||||
String msg = "System package " + pkg.packageName
|
||||
+ " has changed from uid: "
|
||||
@@ -2591,12 +2694,12 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
+ mOutPermissions[1] + " on disk, "
|
||||
+ pkg.applicationInfo.uid + " in settings";
|
||||
synchronized (mPackages) {
|
||||
if (!mReportedUidError) {
|
||||
mReportedUidError = true;
|
||||
msg = msg + "; read messages:\n"
|
||||
+ mSettings.getReadMessagesLP();
|
||||
mSettings.mReadMessages.append(msg);
|
||||
mSettings.mReadMessages.append('\n');
|
||||
uidError = true;
|
||||
if (!pkgSetting.uidError) {
|
||||
reportSettingsProblem(Log.ERROR, msg);
|
||||
}
|
||||
reportSettingsProblem(Log.ERROR, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2604,6 +2707,29 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
} else {
|
||||
if ((parseFlags&PackageParser.PARSE_CHATTY) != 0 && Config.LOGV)
|
||||
Log.v(TAG, "Want this data dir: " + dataPath);
|
||||
if (pkgSetting.origPackage != null) {
|
||||
synchronized (mPackages) {
|
||||
// This package is being update from another; rename the
|
||||
// old one's data dir.
|
||||
String msg = "Transfering data from old package "
|
||||
+ pkgSetting.origPackage.name + " to new package "
|
||||
+ pkgSetting.name;
|
||||
reportSettingsProblem(Log.WARN, msg);
|
||||
if (mInstaller != null) {
|
||||
int ret = mInstaller.rename(pkgSetting.origPackage.name,
|
||||
pkgName, useEncryptedFSDir);
|
||||
if(ret < 0) {
|
||||
msg = "Error transfering data from old package "
|
||||
+ pkgSetting.origPackage.name + " to new package "
|
||||
+ pkgSetting.name;
|
||||
reportSettingsProblem(Log.WARN, msg);
|
||||
}
|
||||
}
|
||||
// And now uninstall the old package.
|
||||
mInstaller.remove(pkgSetting.origPackage.name, useEncryptedFSDir);
|
||||
mSettings.removePackageLP(pkgSetting.origPackage.name);
|
||||
}
|
||||
}
|
||||
//invoke installer to do the actual installation
|
||||
if (mInstaller != null) {
|
||||
int ret = mInstaller.install(pkgName, useEncryptedFSDir, pkg.applicationInfo.uid,
|
||||
@@ -2629,8 +2755,16 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
pkg.applicationInfo.dataDir = null;
|
||||
}
|
||||
}
|
||||
|
||||
pkgSetting.uidError = uidError;
|
||||
}
|
||||
|
||||
// No longer need to retain this.
|
||||
if (pkgSetting.origPackage != null) {
|
||||
mTransferedPackages.add(pkgSetting.origPackage.name);
|
||||
pkgSetting.origPackage = null;
|
||||
}
|
||||
|
||||
// Perform shared library installation and dex validation and
|
||||
// optimization, if this is not a system app.
|
||||
if (mInstaller != null) {
|
||||
@@ -5951,16 +6085,31 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pw.println(" ");
|
||||
pw.println("Settings parse messages:");
|
||||
pw.println(mSettings.mReadMessages.toString());
|
||||
|
||||
pw.println(" ");
|
||||
pw.println("Package warning messages:");
|
||||
File fname = getSettingsProblemFile();
|
||||
FileInputStream in;
|
||||
try {
|
||||
in = new FileInputStream(fname);
|
||||
int avail = in.available();
|
||||
byte[] data = new byte[avail];
|
||||
in.read(data);
|
||||
pw.println(new String(data));
|
||||
} catch (FileNotFoundException e) {
|
||||
} catch (IOException e) {
|
||||
}
|
||||
}
|
||||
|
||||
synchronized (mProviders) {
|
||||
pw.println(" ");
|
||||
pw.println("Registered ContentProviders:");
|
||||
for (PackageParser.Provider p : mProviders.values()) {
|
||||
pw.println(" ["); pw.println(p.info.authority); pw.println("]: ");
|
||||
pw.print(" ["); pw.print(p.info.authority); pw.print("]: ");
|
||||
pw.println(p.toString());
|
||||
}
|
||||
}
|
||||
@@ -5972,7 +6121,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
final static int TYPE_DYNAMIC = 2;
|
||||
|
||||
final String name;
|
||||
final String sourcePackage;
|
||||
String sourcePackage;
|
||||
final int type;
|
||||
PackageParser.Permission perm;
|
||||
PermissionInfo pendingInfo;
|
||||
@@ -6437,6 +6586,8 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
private String timeStampString = "0";
|
||||
int versionCode;
|
||||
|
||||
boolean uidError;
|
||||
|
||||
PackageSignatures signatures = new PackageSignatures();
|
||||
|
||||
boolean permissionsFixed;
|
||||
@@ -6448,6 +6599,8 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
int enabled = COMPONENT_ENABLED_STATE_DEFAULT;
|
||||
int installStatus = PKG_INSTALL_COMPLETE;
|
||||
|
||||
PackageSettingBase origPackage;
|
||||
|
||||
/* package name of the app that installed this package */
|
||||
String installerPackageName;
|
||||
|
||||
@@ -6455,13 +6608,17 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
int pVersionCode, int pkgFlags) {
|
||||
super(pkgFlags);
|
||||
this.name = name;
|
||||
init(codePath, resourcePath, pVersionCode);
|
||||
}
|
||||
|
||||
void init(File codePath, File resourcePath, int pVersionCode) {
|
||||
this.codePath = codePath;
|
||||
this.codePathString = codePath.toString();
|
||||
this.resourcePath = resourcePath;
|
||||
this.resourcePathString = resourcePath.toString();
|
||||
this.versionCode = pVersionCode;
|
||||
}
|
||||
|
||||
|
||||
public void setInstallerPackageName(String packageName) {
|
||||
installerPackageName = packageName;
|
||||
}
|
||||
@@ -6667,11 +6824,11 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
mBackupSettingsFilename = new File(systemDir, "packages-backup.xml");
|
||||
}
|
||||
|
||||
PackageSetting getPackageLP(PackageParser.Package pkg,
|
||||
PackageSetting getPackageLP(PackageParser.Package pkg, PackageSetting origPackage,
|
||||
SharedUserSetting sharedUser, File codePath, File resourcePath,
|
||||
int pkgFlags, boolean create, boolean add) {
|
||||
final String name = pkg.packageName;
|
||||
PackageSetting p = getPackageLP(name, sharedUser, codePath,
|
||||
PackageSetting p = getPackageLP(name, origPackage, sharedUser, codePath,
|
||||
resourcePath, pkg.mVersionCode, pkgFlags, create, add);
|
||||
return p;
|
||||
}
|
||||
@@ -6813,7 +6970,31 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
return null;
|
||||
}
|
||||
|
||||
private PackageSetting getPackageLP(String name,
|
||||
// Transfer ownership of permissions from one package to another.
|
||||
private void transferPermissions(String origPkg, String newPkg) {
|
||||
// Transfer ownership of permissions to the new package.
|
||||
for (int i=0; i<2; i++) {
|
||||
HashMap<String, BasePermission> permissions =
|
||||
i == 0 ? mPermissionTrees : mPermissions;
|
||||
for (BasePermission bp : permissions.values()) {
|
||||
if (origPkg.equals(bp.sourcePackage)) {
|
||||
if (DEBUG_UPGRADE) Log.v(TAG,
|
||||
"Moving permission " + bp.name
|
||||
+ " from pkg " + bp.sourcePackage
|
||||
+ " to " + newPkg);
|
||||
bp.sourcePackage = newPkg;
|
||||
bp.perm = null;
|
||||
if (bp.pendingInfo != null) {
|
||||
bp.sourcePackage = newPkg;
|
||||
}
|
||||
bp.uid = 0;
|
||||
bp.gids = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PackageSetting getPackageLP(String name, PackageSetting origPackage,
|
||||
SharedUserSetting sharedUser, File codePath, File resourcePath,
|
||||
int vc, int pkgFlags, boolean create, boolean add) {
|
||||
PackageSetting p = mPackages.get(name);
|
||||
@@ -6857,36 +7038,49 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
return null;
|
||||
}
|
||||
p = new PackageSetting(name, codePath, resourcePath, vc, pkgFlags);
|
||||
p.setTimeStamp(codePath.lastModified());
|
||||
p.sharedUser = sharedUser;
|
||||
if (sharedUser != null) {
|
||||
p.userId = sharedUser.userId;
|
||||
} else if (MULTIPLE_APPLICATION_UIDS) {
|
||||
// Clone the setting here for disabled system packages
|
||||
PackageSetting dis = mDisabledSysPackages.get(name);
|
||||
if (dis != null) {
|
||||
// For disabled packages a new setting is created
|
||||
// from the existing user id. This still has to be
|
||||
// added to list of user id's
|
||||
// Copy signatures from previous setting
|
||||
if (dis.signatures.mSignatures != null) {
|
||||
p.signatures.mSignatures = dis.signatures.mSignatures.clone();
|
||||
}
|
||||
p.userId = dis.userId;
|
||||
// Clone permissions
|
||||
p.grantedPermissions = new HashSet<String>(dis.grantedPermissions);
|
||||
p.loadedPermissions = new HashSet<String>(dis.loadedPermissions);
|
||||
// Clone component info
|
||||
p.disabledComponents = new HashSet<String>(dis.disabledComponents);
|
||||
p.enabledComponents = new HashSet<String>(dis.enabledComponents);
|
||||
// Add new setting to list of user ids
|
||||
addUserIdLP(p.userId, p, name);
|
||||
} else {
|
||||
// Assign new user id
|
||||
p.userId = newUserIdLP(p);
|
||||
}
|
||||
if (origPackage != null) {
|
||||
// We are consuming the data from an existing package.
|
||||
if (DEBUG_UPGRADE) Log.v(TAG, "Package " + name
|
||||
+ " is adopting original package " + origPackage.name);
|
||||
p.copyFrom(origPackage);
|
||||
p.sharedUser = origPackage.sharedUser;
|
||||
p.userId = origPackage.userId;
|
||||
p.origPackage = origPackage;
|
||||
transferPermissions(origPackage.name, name);
|
||||
// Update new package state.
|
||||
p.setTimeStamp(codePath.lastModified());
|
||||
} else {
|
||||
p.userId = FIRST_APPLICATION_UID;
|
||||
p.setTimeStamp(codePath.lastModified());
|
||||
p.sharedUser = sharedUser;
|
||||
if (sharedUser != null) {
|
||||
p.userId = sharedUser.userId;
|
||||
} else if (MULTIPLE_APPLICATION_UIDS) {
|
||||
// Clone the setting here for disabled system packages
|
||||
PackageSetting dis = mDisabledSysPackages.get(name);
|
||||
if (dis != null) {
|
||||
// For disabled packages a new setting is created
|
||||
// from the existing user id. This still has to be
|
||||
// added to list of user id's
|
||||
// Copy signatures from previous setting
|
||||
if (dis.signatures.mSignatures != null) {
|
||||
p.signatures.mSignatures = dis.signatures.mSignatures.clone();
|
||||
}
|
||||
p.userId = dis.userId;
|
||||
// Clone permissions
|
||||
p.grantedPermissions = new HashSet<String>(dis.grantedPermissions);
|
||||
p.loadedPermissions = new HashSet<String>(dis.loadedPermissions);
|
||||
// Clone component info
|
||||
p.disabledComponents = new HashSet<String>(dis.disabledComponents);
|
||||
p.enabledComponents = new HashSet<String>(dis.enabledComponents);
|
||||
// Add new setting to list of user ids
|
||||
addUserIdLP(p.userId, p, name);
|
||||
} else {
|
||||
// Assign new user id
|
||||
p.userId = newUserIdLP(p);
|
||||
}
|
||||
} else {
|
||||
p.userId = FIRST_APPLICATION_UID;
|
||||
}
|
||||
}
|
||||
if (p.userId < 0) {
|
||||
reportSettingsProblem(Log.WARN,
|
||||
@@ -7248,6 +7442,9 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
serializer.attribute(null, "sharedUserId",
|
||||
Integer.toString(pkg.userId));
|
||||
}
|
||||
if (pkg.uidError) {
|
||||
serializer.attribute(null, "uidError", "true");
|
||||
}
|
||||
if (pkg.enabled != COMPONENT_ENABLED_STATE_DEFAULT) {
|
||||
serializer.attribute(null, "enabled",
|
||||
pkg.enabled == COMPONENT_ENABLED_STATE_ENABLED
|
||||
@@ -7441,7 +7638,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
final PendingPackage pp = mPendingPackages.get(i);
|
||||
Object idObj = getUserIdLP(pp.sharedId);
|
||||
if (idObj != null && idObj instanceof SharedUserSetting) {
|
||||
PackageSetting p = getPackageLP(pp.name,
|
||||
PackageSetting p = getPackageLP(pp.name, null,
|
||||
(SharedUserSetting)idObj, pp.codePath, pp.resourcePath,
|
||||
pp.versionCode, pp.pkgFlags, true, true);
|
||||
if (p == null) {
|
||||
@@ -7610,6 +7807,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
String resourcePathStr = null;
|
||||
String systemStr = null;
|
||||
String installerPackageName = null;
|
||||
String uidError = null;
|
||||
int pkgFlags = 0;
|
||||
String timeStampStr;
|
||||
long timeStamp = 0;
|
||||
@@ -7619,6 +7817,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
try {
|
||||
name = parser.getAttributeValue(null, "name");
|
||||
idStr = parser.getAttributeValue(null, "userId");
|
||||
uidError = parser.getAttributeValue(null, "uidError");
|
||||
sharedIdStr = parser.getAttributeValue(null, "sharedUserId");
|
||||
codePathStr = parser.getAttributeValue(null, "codePath");
|
||||
resourcePathStr = parser.getAttributeValue(null, "resourcePath");
|
||||
@@ -7712,6 +7911,7 @@ class PackageManagerService extends IPackageManager.Stub {
|
||||
+ parser.getPositionDescription());
|
||||
}
|
||||
if (packageSetting != null) {
|
||||
packageSetting.uidError = "true".equals(uidError);
|
||||
packageSetting.installerPackageName = installerPackageName;
|
||||
final String enabledStr = parser.getAttributeValue(null, "enabled");
|
||||
if (enabledStr != null) {
|
||||
|
||||
Reference in New Issue
Block a user