From 690d20bb53ba2485f59d128b365eff991d5cc3e6 Mon Sep 17 00:00:00 2001 From: Dianne Hackborn Date: Wed, 22 Dec 2010 14:03:29 -0800 Subject: Fix issue # 3227963: SecurityException: Neither user 10023 nor... ...current process has android.permission.WAKE_LOCK When updating a system app, we would actually uninstall the package of the system app, which also meant removing its uid...! It was just luck that we would get the same uid when installing the update after that. During that time, if anyone tried to do anything related to that uid, it would be unknown. This change tweaks how we go about replacing system apps by making it more like normal apps -- to make this work, if we need to disable the system app, we generate a new PackageSetting from the current system app and replace it into our data structures, so we can update that without trashing the current correct information about the (still actually there) system app. Also fixed a problem where we were not killing the currently running app before installing, like we do when updating a normal application. And fixed a problem where we were not deleting the /data .apk when uninstalling a system app update. And added a new option to the "pm" command to clear the data associated with an app. Change-Id: I0e879677849aa42950a3c360bf78ad820e87674b --- cmds/pm/src/com/android/commands/pm/Pm.java | 59 ++++++++++++++ .../com/android/server/PackageManagerService.java | 92 ++++++++++++++-------- 2 files changed, 118 insertions(+), 33 deletions(-) diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java index 311dc38..326e2c8 100644 --- a/cmds/pm/src/com/android/commands/pm/Pm.java +++ b/cmds/pm/src/com/android/commands/pm/Pm.java @@ -18,9 +18,11 @@ package com.android.commands.pm; import com.android.internal.content.PackageHelper; +import android.app.ActivityManagerNative; import android.content.ComponentName; import android.content.pm.ApplicationInfo; import android.content.pm.FeatureInfo; +import android.content.pm.IPackageDataObserver; import android.content.pm.IPackageDeleteObserver; import android.content.pm.IPackageInstallObserver; import android.content.pm.IPackageManager; @@ -100,6 +102,11 @@ public final class Pm { return; } + if ("clear".equals(op)) { + runClear(); + return; + } + if ("enable".equals(op)) { runSetEnabledSetting(PackageManager.COMPONENT_ENABLED_STATE_ENABLED); return; @@ -809,6 +816,55 @@ public final class Pm { return obs.result; } + class ClearDataObserver extends IPackageDataObserver.Stub { + boolean finished; + boolean result; + + @Override + public void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException { + synchronized (this) { + finished = true; + result = succeeded; + notifyAll(); + } + } + + } + + private void runClear() { + String pkg = nextArg(); + if (pkg == null) { + System.err.println("Error: no package specified"); + showUsage(); + return; + } + + ClearDataObserver obs = new ClearDataObserver(); + try { + if (!ActivityManagerNative.getDefault().clearApplicationUserData(pkg, obs)) { + System.err.println("Failed"); + } + + synchronized (obs) { + while (!obs.finished) { + try { + obs.wait(); + } catch (InterruptedException e) { + } + } + } + + if (obs.result) { + System.err.println("Success"); + } else { + System.err.println("Failed"); + } + } catch (RemoteException e) { + System.err.println(e.toString()); + System.err.println(PM_NOT_RUNNING_ERR); + } + } + private static String enabledSettingToString(int state) { switch (state) { case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT: @@ -944,6 +1000,7 @@ public final class Pm { System.err.println(" pm path PACKAGE"); System.err.println(" pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] PATH"); System.err.println(" pm uninstall [-k] PACKAGE"); + System.err.println(" pm clear PACKAGE"); System.err.println(" pm enable PACKAGE_OR_COMPONENT"); System.err.println(" pm disable PACKAGE_OR_COMPONENT"); System.err.println(" pm setInstallLocation [0/auto] [1/internal] [2/external]"); @@ -986,6 +1043,8 @@ public final class Pm { System.err.println(" -k: keep the data and cache directories around."); System.err.println("after the package removal."); System.err.println(""); + System.err.println("The clear command deletes all data associated with a package."); + System.err.println(""); System.err.println("The enable and disable commands change the enabled state of"); System.err.println("a given package or component (written as \"package/class\")."); System.err.println(""); diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index b0f3a23..cb9dfc8 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -3663,17 +3663,6 @@ class PackageManagerService extends IPackageManager.Stub { mAppDirs.remove(pkg.mPath); } - PackageSetting ps = (PackageSetting)pkg.mExtras; - if (ps != null && ps.sharedUser != null) { - // XXX don't do this until the data is removed. - if (false) { - ps.sharedUser.packages.remove(ps); - if (ps.sharedUser.packages.size() == 0) { - // Remove. - } - } - } - int N = pkg.providers.size(); StringBuilder r = null; int i; @@ -5695,12 +5684,26 @@ class PackageManagerService extends IPackageManager.Stub { return; } } + + killApplication(packageName, oldPkg.applicationInfo.uid); + res.removedInfo.uid = oldPkg.applicationInfo.uid; res.removedInfo.removedPackage = packageName; // Remove existing system package removePackageLI(oldPkg, true); synchronized (mPackages) { - mSettings.disableSystemPackageLP(packageName); + if (!mSettings.disableSystemPackageLP(packageName) && deletedPackage != null) { + // We didn't need to disable the .apk as a current system package, + // which means we are replacing another update that is already + // installed. We need to make sure to delete the older one's .apk. + res.removedInfo.args = createInstallArgs(isExternal(pkg) + ? PackageManager.INSTALL_EXTERNAL : PackageManager.INSTALL_INTERNAL, + deletedPackage.applicationInfo.sourceDir, + deletedPackage.applicationInfo.publicSourceDir, + deletedPackage.applicationInfo.nativeLibraryDir); + } else { + res.removedInfo.args = null; + } } // Successfully disabled the old package. Now proceed with re-installation @@ -5739,17 +5742,6 @@ class PackageManagerService extends IPackageManager.Stub { } mSettings.writeLP(); } - } else { - // If this is an update to an existing update, setup - // to remove the existing update. - synchronized (mPackages) { - PackageSetting ps = mSettings.getDisabledSystemPkg(packageName); - if (ps != null && ps.codePathString != null && - !ps.codePathString.equals(oldPkgSetting.codePathString)) { - res.removedInfo.args = createInstallArgs(0, oldPkgSetting.codePathString, - oldPkgSetting.resourcePathString, oldPkgSetting.nativeLibraryPathString); - } - } } } @@ -6252,24 +6244,21 @@ class PackageManagerService extends IPackageManager.Stub { ps = mSettings.getDisabledSystemPkg(p.packageName); } if (ps == null) { - Slog.w(TAG, "Attempt to delete system package "+ p.packageName); + Slog.w(TAG, "Attempt to delete unknown system package "+ p.packageName); return false; } else { Log.i(TAG, "Deleting system pkg from data partition"); } // Delete the updated package outInfo.isRemovedPackageSystemUpdate = true; - final boolean deleteCodeAndResources; if (ps.versionCode < p.mVersionCode) { - // Delete code and resources for downgrades - deleteCodeAndResources = true; + // Delete data for downgrades flags &= ~PackageManager.DONT_DELETE_DATA; } else { // Preserve data by setting flag - deleteCodeAndResources = false; flags |= PackageManager.DONT_DELETE_DATA; } - boolean ret = deleteInstalledPackageLI(p, deleteCodeAndResources, flags, outInfo, + boolean ret = deleteInstalledPackageLI(p, true, flags, outInfo, writeSettings); if (!ret) { return false; @@ -7850,6 +7839,12 @@ class PackageManagerService extends IPackageManager.Stub { pkgFlags); } + PackageSetting(PackageSetting orig) { + super(orig.name, orig.realName, orig.codePath, orig.resourcePath, + orig.nativeLibraryPathString, orig.versionCode, orig.pkgFlags); + copyFrom(orig); + } + @Override public String toString() { return "PackageSetting{" @@ -8062,21 +8057,29 @@ class PackageManagerService extends IPackageManager.Stub { return s; } - int disableSystemPackageLP(String name) { + boolean disableSystemPackageLP(String name) { PackageSetting p = mPackages.get(name); if(p == null) { Log.w(TAG, "Package:"+name+" is not an installed package"); - return -1; + return false; } PackageSetting dp = mDisabledSysPackages.get(name); // always make sure the system package code and resource paths dont change - if(dp == null) { + if (dp == null) { if((p.pkg != null) && (p.pkg.applicationInfo != null)) { p.pkg.applicationInfo.flags |= ApplicationInfo.FLAG_UPDATED_SYSTEM_APP; } mDisabledSysPackages.put(name, p); + + // a little trick... when we install the new package, we don't + // want to modify the existing PackageSetting for the built-in + // version. so at this point we need a new PackageSetting that + // is okay to much with. + PackageSetting newp = new PackageSetting(p); + replacePackageLP(name, newp); + return true; } - return removePackageLP(name); + return false; } PackageSetting enableSystemPackageLP(String name) { @@ -8410,6 +8413,19 @@ class PackageManagerService extends IPackageManager.Stub { return -1; } + private void replacePackageLP(String name, PackageSetting newp) { + PackageSetting p = mPackages.get(name); + if (p != null) { + if (p.sharedUser != null) { + p.sharedUser.packages.remove(p); + p.sharedUser.packages.add(newp); + } else { + replaceUserIdLP(p.userId, newp); + } + } + mPackages.put(name, newp); + } + private boolean addUserIdLP(int uid, Object obj, Object name) { if (uid >= FIRST_APPLICATION_UID + MAX_APPLICATION_UIDS) { return false; @@ -8472,6 +8488,16 @@ class PackageManagerService extends IPackageManager.Stub { } } + private void replaceUserIdLP(int uid, Object obj) { + if (uid >= FIRST_APPLICATION_UID) { + int N = mUserIds.size(); + final int index = uid - FIRST_APPLICATION_UID; + if (index < N) mUserIds.set(index, obj); + } else { + mOtherUserIds.put(uid, obj); + } + } + void writeLP() { //Debug.startMethodTracing("/data/system/packageprof", 8 * 1024 * 1024); -- cgit v1.1