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
This commit is contained in:
@@ -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("");
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user