Merge "More freezing of apps when doing surgery." into nyc-dev
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index e62450c..bee276e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -247,6 +247,7 @@
import com.android.server.pm.Settings.VersionInfo;
import com.android.server.storage.DeviceStorageMonitorInternal;
+import dalvik.system.CloseGuard;
import dalvik.system.DexFile;
import dalvik.system.VMRuntime;
@@ -298,14 +299,37 @@
import java.util.concurrent.atomic.AtomicLong;
/**
- * Keep track of all those .apks everywhere.
+ * Keep track of all those APKs everywhere.
+ * <p>
+ * Internally there are two important locks:
+ * <ul>
+ * <li>{@link #mPackages} is used to guard all in-memory parsed package details
+ * and other related state. It is a fine-grained lock that should only be held
+ * momentarily, as it's one of the most contended locks in the system.
+ * <li>{@link #mInstallLock} is used to guard all {@code installd} access, whose
+ * operations typically involve heavy lifting of application data on disk. Since
+ * {@code installd} is single-threaded, and it's operations can often be slow,
+ * this lock should never be acquired while already holding {@link #mPackages}.
+ * Conversely, it's safe to acquire {@link #mPackages} momentarily while already
+ * holding {@link #mInstallLock}.
+ * </ul>
+ * Many internal methods rely on the caller to hold the appropriate locks, and
+ * this contract is expressed through method name suffixes:
+ * <ul>
+ * <li>fooLI(): the caller must hold {@link #mInstallLock}
+ * <li>fooLIF(): the caller must hold {@link #mInstallLock} and the package
+ * being modified must be frozen
+ * <li>fooLPr(): the caller must hold {@link #mPackages} for reading
+ * <li>fooLPw(): the caller must hold {@link #mPackages} for writing
+ * </ul>
+ * <p>
+ * Because this class is very central to the platform's security; please run all
+ * CTS and unit tests whenever making modifications:
*
- * This is very central to the platform's security; please run the unit
- * tests whenever making modifications here:
- *
-runtest -c android.content.pm.PackageManagerTests frameworks-core
- *
- * {@hide}
+ * <pre>
+ * $ runtest -c android.content.pm.PackageManagerTests frameworks-core
+ * $ cts-tradefed run commandAndExit cts -m AppSecurityTests
+ * </pre>
*/
public class PackageManagerService extends IPackageManager.Stub {
static final String TAG = "PackageManager";
@@ -367,6 +391,7 @@
static final int SCAN_INITIAL = 1<<14;
static final int SCAN_CHECK_ONLY = 1<<15;
static final int SCAN_DONT_KILL_APP = 1<<17;
+ static final int SCAN_IGNORE_FROZEN = 1<<18;
static final int REMOVE_CHATTY = 1<<16;
@@ -570,7 +595,19 @@
*/
boolean mPromoteSystemApps;
+ @GuardedBy("mPackages")
final Settings mSettings;
+
+ /**
+ * Set of package names that are currently "frozen", which means active
+ * surgery is being done on the code/data for that package. The platform
+ * will refuse to launch frozen packages to avoid race conditions.
+ *
+ * @see PackageFreezer
+ */
+ @GuardedBy("mPackages")
+ final ArraySet<String> mFrozenPackages = new ArraySet<>();
+
boolean mRestoredSettings;
// System configuration read by SystemConfig.
@@ -2352,7 +2389,8 @@
psit.remove();
logCriticalInfo(Log.WARN, "System package " + ps.name
+ " no longer exists; wiping its data");
- removeDataDirsLI(null, ps.name);
+ // No apps are running this early, so no need to freeze
+ removeDataDirsLIF(null, ps.name);
} else {
final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps.name);
if (disabledPs.codePath == null || !disabledPs.codePath.exists()) {
@@ -2364,11 +2402,11 @@
//look for any incomplete package installations
ArrayList<PackageSetting> deletePkgsList = mSettings.getListOfIncompleteInstallPackagesLPr();
- //clean up list
- for(int i = 0; i < deletePkgsList.size(); i++) {
- //clean up here
- cleanupInstallFailedPackage(deletePkgsList.get(i));
+ for (int i = 0; i < deletePkgsList.size(); i++) {
+ // No apps are running this early, so no need to freeze
+ cleanupInstallFailedPackageLIF(deletePkgsList.get(i));
}
+
//delete tmp files
deleteTempPackageFiles();
@@ -2400,7 +2438,8 @@
if (deletedPkg == null) {
msg = "Updated system package " + deletedAppName
+ " no longer exists; wiping its data";
- removeDataDirsLI(null, deletedAppName);
+ // No apps are running this early, so no need to freeze
+ removeDataDirsLIF(null, deletedAppName);
} else {
msg = "Updated system app + " + deletedAppName
+ " no longer present; removing system privileges for "
@@ -2556,7 +2595,8 @@
for (int i = 0; i < mSettings.mPackages.size(); i++) {
final PackageSetting ps = mSettings.mPackages.valueAt(i);
if (Objects.equals(StorageManager.UUID_PRIVATE_INTERNAL, ps.volumeUuid)) {
- deleteCodeCacheDirsLI(ps.volumeUuid, ps.name);
+ // No apps are running this early, so no need to freeze
+ deleteCodeCacheDirsLIF(ps.volumeUuid, ps.name);
}
}
ver.fingerprint = Build.FINGERPRINT;
@@ -2941,10 +2981,10 @@
}
}
- void cleanupInstallFailedPackage(PackageSetting ps) {
+ void cleanupInstallFailedPackageLIF(PackageSetting ps) {
logCriticalInfo(Log.WARN, "Cleaning up incompletely installed app: " + ps.name);
- removeDataDirsLI(ps.volumeUuid, ps.name);
+ removeDataDirsLIF(ps.volumeUuid, ps.name);
if (ps.codePath != null) {
removeCodePathLI(ps.codePath);
}
@@ -2954,7 +2994,9 @@
}
ps.resourcePath.delete();
}
- mSettings.removePackageLPw(ps.name);
+ synchronized (mPackages) {
+ mSettings.removePackageLPw(ps.name);
+ }
}
static int[] appendInts(int[] cur, int[] add) {
@@ -3006,7 +3048,7 @@
throw new SecurityException("Package " + packageName + " not a system app!");
}
- if (ps.frozen) {
+ if (mFrozenPackages.contains(packageName)) {
throw new SecurityException("Package " + packageName + " is currently frozen!");
}
@@ -4403,6 +4445,13 @@
}
}
+ /**
+ * This method should typically only be used when granting or revoking
+ * permissions, since the app may immediately restart after this call.
+ * <p>
+ * If you're doing surgery on app code/data, use {@link PackageFreezer} to
+ * guard your work against the app being relaunched.
+ */
private void killUid(int appId, int userId, String reason) {
final long identity = Binder.clearCallingIdentity();
try {
@@ -6800,7 +6849,10 @@
!= PackageManager.SIGNATURE_MATCH) {
logCriticalInfo(Log.WARN, "Package " + ps.name + " appeared on system, but"
+ " signatures don't match existing userdata copy; removing");
- deletePackageLI(pkg.packageName, null, true, null, 0, null, false, null);
+ try (PackageFreezer freezer = freezePackage(pkg.packageName,
+ "scanPackageInternalLI")) {
+ deletePackageLIF(pkg.packageName, null, true, null, 0, null, false, null);
+ }
ps = null;
} else {
/*
@@ -7269,15 +7321,15 @@
return true;
}
- private boolean removeDataDirsLI(String volumeUuid, String packageName) {
+ private boolean removeDataDirsLIF(String volumeUuid, String packageName) {
// TODO: triage flags as part of 26466827
final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
boolean res = true;
- final int[] users = sUserManager.getUserIds();
- for (int user : users) {
+ final int[] userIds = sUserManager.getUserIds();
+ for (int userId : userIds) {
try {
- mInstaller.destroyAppData(volumeUuid, packageName, user, flags);
+ mInstaller.destroyAppData(volumeUuid, packageName, userId, flags);
} catch (InstallerException e) {
Slog.w(TAG, "Failed to delete data directory", e);
res = false;
@@ -7299,10 +7351,12 @@
}
void destroyAppDataLI(String volumeUuid, String packageName, int userId, int flags) {
- try {
- mInstaller.destroyAppData(volumeUuid, packageName, userId, flags);
- } catch (InstallerException e) {
- Slog.w(TAG, "Failed to destroy app data", e);
+ try (PackageFreezer freezer = freezePackage(packageName, "destroyAppDataLI")) {
+ try {
+ mInstaller.destroyAppData(volumeUuid, packageName, userId, flags);
+ } catch (InstallerException e) {
+ Slog.w(TAG, "Failed to destroy app data", e);
+ }
}
}
@@ -7315,19 +7369,7 @@
}
}
- private void deleteProfilesLI(String packageName, boolean destroy) {
- final PackageParser.Package pkg;
- synchronized (mPackages) {
- pkg = mPackages.get(packageName);
- }
- if (pkg == null) {
- Slog.w(TAG, "Failed to delete profiles. No package: " + packageName);
- return;
- }
- deleteProfilesLI(pkg, destroy);
- }
-
- private void deleteProfilesLI(PackageParser.Package pkg, boolean destroy) {
+ private void deleteProfilesLIF(PackageParser.Package pkg, boolean destroy) {
try {
if (destroy) {
mInstaller.destroyAppProfiles(pkg.packageName);
@@ -7339,7 +7381,7 @@
}
}
- private void deleteCodeCacheDirsLI(String volumeUuid, String packageName) {
+ private void deleteCodeCacheDirsLIF(String volumeUuid, String packageName) {
final PackageParser.Package pkg;
synchronized (mPackages) {
pkg = mPackages.get(packageName);
@@ -7348,10 +7390,10 @@
Slog.w(TAG, "Failed to delete code cache directory. No package: " + packageName);
return;
}
- deleteCodeCacheDirsLI(pkg);
+ deleteCodeCacheDirsLIF(pkg);
}
- private void deleteCodeCacheDirsLI(PackageParser.Package pkg) {
+ private void deleteCodeCacheDirsLIF(PackageParser.Package pkg) {
// TODO: triage flags as part of 26466827
final int flags = StorageManager.FLAG_STORAGE_CE | StorageManager.FLAG_STORAGE_DE;
@@ -7564,7 +7606,8 @@
return res;
} finally {
if (!success && (scanFlags & SCAN_DELETE_DATA_ON_FAILURES) != 0) {
- removeDataDirsLI(pkg.volumeUuid, pkg.packageName);
+ // DELETE_DATA_ON_FAILURES is only used by frozen paths
+ removeDataDirsLIF(pkg.volumeUuid, pkg.packageName);
}
}
}
@@ -8121,20 +8164,17 @@
}
}
- // Request the ActivityManager to kill the process(only for existing packages)
- // so that we do not end up in a confused state while the user is still using the older
- // version of the application while the new one gets installed.
- final boolean isReplacing = (scanFlags & SCAN_REPLACING) != 0;
- final boolean killApp = (scanFlags & SCAN_DONT_KILL_APP) == 0;
- if (killApp) {
- if (isReplacing) {
- Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "killApplication");
-
- killApplication(pkg.applicationInfo.packageName,
- pkg.applicationInfo.uid, "replace pkg");
-
- Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
- }
+ if ((scanFlags & SCAN_BOOTING) != 0) {
+ // No apps can run during boot scan, so they don't need to be frozen
+ } else if ((scanFlags & SCAN_DONT_KILL_APP) != 0) {
+ // Caller asked to not kill app, so it's probably not frozen
+ } else if ((scanFlags & SCAN_IGNORE_FROZEN) != 0) {
+ // Caller asked us to ignore frozen check for some reason; they
+ // probably didn't know the package name
+ } else {
+ // We're doing major surgery on this package, so it better be frozen
+ // right now to keep it from launching
+ checkPackageFrozen(pkgName);
}
// Also need to kill any apps that are dependent on the library.
@@ -9001,27 +9041,21 @@
}
}
- private void killPackage(PackageParser.Package pkg, String reason) {
- // Kill the parent package
- killApplication(pkg.packageName, pkg.applicationInfo.uid, reason);
- // Kill the child packages
- final int childCount = (pkg.childPackages != null) ? pkg.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- PackageParser.Package childPkg = pkg.childPackages.get(i);
- killApplication(childPkg.packageName, childPkg.applicationInfo.uid, reason);
- }
- }
-
private void killApplication(String pkgName, int appId, String reason) {
// Request the ActivityManager to kill the process(only for existing packages)
// so that we do not end up in a confused state while the user is still using the older
// version of the application while the new one gets installed.
- IActivityManager am = ActivityManagerNative.getDefault();
- if (am != null) {
- try {
- am.killApplicationWithAppId(pkgName, appId, reason);
- } catch (RemoteException e) {
+ final long token = Binder.clearCallingIdentity();
+ try {
+ IActivityManager am = ActivityManagerNative.getDefault();
+ if (am != null) {
+ try {
+ am.killApplicationWithAppId(pkgName, appId, reason);
+ } catch (RemoteException e) {
+ }
}
+ } finally {
+ Binder.restoreCallingIdentity(token);
}
}
@@ -13330,7 +13364,8 @@
Slog.d(TAG, "Cleaning up " + move.packageName + " on " + volumeUuid);
synchronized (mInstallLock) {
// Clean up both app data and code
- removeDataDirsLI(volumeUuid, move.packageName);
+ // All package moves are frozen until finished
+ removeDataDirsLIF(volumeUuid, move.packageName);
removeCodePathLI(codeFile);
}
return true;
@@ -13475,7 +13510,7 @@
/*
* Install a non-existing package.
*/
- private void installNewPackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
+ private void installNewPackageLIF(PackageParser.Package pkg, int parseFlags, int scanFlags,
UserHandle user, String installerPackageName, String volumeUuid,
PackageInstalledInfo res) {
Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "installNewPackage");
@@ -13516,7 +13551,7 @@
} else {
// Remove package from internal structures, but keep around any
// data that might have already existed
- deletePackageLI(pkgName, UserHandle.ALL, false, null,
+ deletePackageLIF(pkgName, UserHandle.ALL, false, null,
PackageManager.DELETE_KEEP_DATA, res.removedInfo, true, null);
}
} catch (PackageManagerException e) {
@@ -13562,14 +13597,13 @@
return false;
}
- private void replacePackageLI(PackageParser.Package pkg, int parseFlags, int scanFlags,
+ private void replacePackageLIF(PackageParser.Package pkg, int parseFlags, int scanFlags,
UserHandle user, String installerPackageName, PackageInstalledInfo res) {
final boolean isEphemeral = (parseFlags & PackageParser.PARSE_IS_EPHEMERAL) != 0;
final PackageParser.Package oldPackage;
final String pkgName = pkg.packageName;
final int[] allUsers;
- final boolean weFroze;
// First find the old package info and check signatures
synchronized(mPackages) {
@@ -13602,32 +13636,8 @@
// In case of rollback, remember per-user/profile install state
allUsers = sUserManager.getUserIds();
-
- // Mark the app as frozen to prevent launching during the upgrade
- // process, and then kill all running instances
- if (!ps.frozen) {
- ps.frozen = true;
- weFroze = true;
- } else {
- weFroze = false;
- }
}
- try {
- replacePackageDirtyLI(pkg, oldPackage, parseFlags, scanFlags, user, allUsers,
- installerPackageName, res);
- } finally {
- // Regardless of success or failure of upgrade steps above, always
- // unfreeze the package if we froze it
- if (weFroze) {
- unfreezePackage(pkgName);
- }
- }
- }
-
- private void replacePackageDirtyLI(PackageParser.Package pkg, PackageParser.Package oldPackage,
- int parseFlags, int scanFlags, UserHandle user, int[] allUsers,
- String installerPackageName, PackageInstalledInfo res) {
// Update what is removed
res.removedInfo = new PackageRemovedInfo();
res.removedInfo.uid = oldPackage.applicationInfo.uid;
@@ -13667,10 +13677,10 @@
boolean sysPkg = (isSystemApp(oldPackage));
if (sysPkg) {
- replaceSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags,
+ replaceSystemPackageLIF(oldPackage, pkg, parseFlags, scanFlags,
user, allUsers, installerPackageName, res);
} else {
- replaceNonSystemPackageLI(oldPackage, pkg, parseFlags, scanFlags,
+ replaceNonSystemPackageLIF(oldPackage, pkg, parseFlags, scanFlags,
user, allUsers, installerPackageName, res);
}
}
@@ -13684,7 +13694,7 @@
return result;
}
- private void replaceNonSystemPackageLI(PackageParser.Package deletedPackage,
+ private void replaceNonSystemPackageLIF(PackageParser.Package deletedPackage,
PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user,
int[] allUsers, String installerPackageName, PackageInstalledInfo res) {
if (DEBUG_INSTALL) Slog.d(TAG, "replaceNonSystemPackageLI: new=" + pkg + ", old="
@@ -13702,7 +13712,7 @@
? ((PackageSetting)pkg.mExtras).lastUpdateTime : 0;
// First delete the existing package while retaining the data directory
- if (!deletePackageLI(pkgName, null, true, allUsers, deleteFlags,
+ if (!deletePackageLIF(pkgName, null, true, allUsers, deleteFlags,
res.removedInfo, true, pkg)) {
// If the existing package wasn't successfully deleted
res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE, "replaceNonSystemPackageLI");
@@ -13722,8 +13732,8 @@
sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
}
- deleteCodeCacheDirsLI(pkg);
- deleteProfilesLI(pkg, /*destroy*/ false);
+ deleteCodeCacheDirsLIF(pkg);
+ deleteProfilesLIF(pkg, /*destroy*/ false);
try {
final PackageParser.Package newPackage = scanPackageTracedLI(pkg, parseFlags,
@@ -13762,7 +13772,7 @@
// Revert all internal state mutations and added folders for the failed install
if (addedPkg) {
- deletePackageLI(pkgName, null, true, allUsers, deleteFlags,
+ deletePackageLIF(pkgName, null, true, allUsers, deleteFlags,
res.removedInfo, true, null);
}
@@ -13822,7 +13832,7 @@
}
}
- private void replaceSystemPackageLI(PackageParser.Package deletedPackage,
+ private void replaceSystemPackageLIF(PackageParser.Package deletedPackage,
PackageParser.Package pkg, int parseFlags, int scanFlags, UserHandle user,
int[] allUsers, String installerPackageName, PackageInstalledInfo res) {
if (DEBUG_INSTALL) Slog.d(TAG, "replaceSystemPackageLI: new=" + pkg
@@ -13837,9 +13847,6 @@
parseFlags |= PackageParser.PARSE_IS_PRIVILEGED;
}
- // Kill package processes including services, providers, etc.
- killPackage(deletedPackage, "replace sys pkg");
-
// Remove existing system package
removePackageLI(deletedPackage, true);
@@ -13857,8 +13864,8 @@
}
// Successfully disabled the old package. Now proceed with re-installation
- deleteCodeCacheDirsLI(pkg);
- deleteProfilesLI(pkg, /*destroy*/ false);
+ deleteCodeCacheDirsLIF(pkg);
+ deleteProfilesLIF(pkg, /*destroy*/ false);
res.setReturnCode(PackageManager.INSTALL_SUCCEEDED);
pkg.setApplicationInfoFlags(ApplicationInfo.FLAG_UPDATED_SYSTEM_APP,
@@ -13907,7 +13914,7 @@
if (ps != null && res.removedInfo.removedChildPackages != null) {
PackageRemovedInfo removedChildRes = res.removedInfo
.removedChildPackages.get(deletedChildPkg.packageName);
- removePackageDataLI(ps, allUsers, removedChildRes, 0, false);
+ removePackageDataLIF(ps, allUsers, removedChildRes, 0, false);
removedChildRes.removedForAllUsers = mPackages.get(ps.name) == null;
}
}
@@ -14514,12 +14521,15 @@
startIntentFilterVerifications(args.user.getIdentifier(), replace, pkg);
- if (replace) {
- replacePackageLI(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
- installerPackageName, res);
- } else {
- installNewPackageLI(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
- args.user, installerPackageName, volumeUuid, res);
+ try (PackageFreezer freezer = freezePackageForInstall(pkgName, installFlags,
+ "installPackageLI")) {
+ if (replace) {
+ replacePackageLIF(pkg, parseFlags, scanFlags | SCAN_REPLACING, args.user,
+ installerPackageName, res);
+ } else {
+ installNewPackageLIF(pkg, parseFlags, scanFlags | SCAN_DELETE_DATA_ON_FAILURES,
+ args.user, installerPackageName, volumeUuid, res);
+ }
}
synchronized (mPackages) {
final PackageSetting ps = mSettings.mPackages.get(pkgName);
@@ -14767,13 +14777,13 @@
@Override
public void deletePackage(final String packageName,
- final IPackageDeleteObserver2 observer, final int userId, final int flags) {
+ final IPackageDeleteObserver2 observer, final int userId, final int deleteFlags) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.DELETE_PACKAGES, null);
Preconditions.checkNotNull(packageName);
Preconditions.checkNotNull(observer);
final int uid = Binder.getCallingUid();
- final boolean deleteAllUsers = (flags & PackageManager.DELETE_ALL_USERS) != 0;
+ final boolean deleteAllUsers = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0;
final int[] users = deleteAllUsers ? sUserManager.getUserIds() : new int[]{ userId };
if (UserHandle.getUserId(uid) != userId || (deleteAllUsers && users.length > 1)) {
mContext.enforceCallingOrSelfPermission(
@@ -14809,15 +14819,15 @@
mHandler.removeCallbacks(this);
int returnCode;
if (!deleteAllUsers) {
- returnCode = deletePackageX(packageName, userId, flags);
+ returnCode = deletePackageX(packageName, userId, deleteFlags);
} else {
int[] blockUninstallUserIds = getBlockUninstallForUsers(packageName, users);
// If nobody is blocking uninstall, proceed with delete for all users
if (ArrayUtils.isEmpty(blockUninstallUserIds)) {
- returnCode = deletePackageX(packageName, userId, flags);
+ returnCode = deletePackageX(packageName, userId, deleteFlags);
} else {
// Otherwise uninstall individually for users with blockUninstalls=false
- final int userFlags = flags & ~PackageManager.DELETE_ALL_USERS;
+ final int userFlags = deleteFlags & ~PackageManager.DELETE_ALL_USERS;
for (int userId : users) {
if (!ArrayUtils.contains(blockUninstallUserIds, userId)) {
returnCode = deletePackageX(packageName, userId, userFlags);
@@ -14908,11 +14918,11 @@
* persisting settings for later use
* sending a broadcast if necessary
*/
- private int deletePackageX(String packageName, int userId, int flags) {
+ private int deletePackageX(String packageName, int userId, int deleteFlags) {
final PackageRemovedInfo info = new PackageRemovedInfo();
final boolean res;
- final UserHandle removeForUser = (flags & PackageManager.DELETE_ALL_USERS) != 0
+ final UserHandle removeForUser = (deleteFlags & PackageManager.DELETE_ALL_USERS) != 0
? UserHandle.ALL : new UserHandle(userId);
if (isPackageDeviceAdmin(packageName, removeForUser.getIdentifier())) {
@@ -14937,8 +14947,11 @@
synchronized (mInstallLock) {
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageX: pkg=" + packageName + " user=" + userId);
- res = deletePackageLI(packageName, removeForUser, true, allUsers,
- flags | REMOVE_CHATTY, info, true, null);
+ try (PackageFreezer freezer = freezePackageForDelete(packageName, deleteFlags,
+ "deletePackageX")) {
+ res = deletePackageLIF(packageName, removeForUser, true, allUsers,
+ deleteFlags | REMOVE_CHATTY, info, true, null);
+ }
synchronized (mPackages) {
if (res) {
mEphemeralApplicationRegistry.onPackageUninstalledLPw(uninstalledPs.pkg);
@@ -14947,7 +14960,7 @@
}
if (res) {
- final boolean killApp = (flags & PackageManager.INSTALL_DONT_KILL_APP) == 0;
+ final boolean killApp = (deleteFlags & PackageManager.DELETE_DONT_KILL_APP) == 0;
info.sendPackageRemovedBroadcasts(killApp);
info.sendSystemPackageUpdatedBroadcasts();
info.sendSystemPackageAppearedBroadcasts();
@@ -15057,7 +15070,7 @@
* make sure this flag is set for partially installed apps. If not its meaningless to
* delete a partially installed application.
*/
- private void removePackageDataLI(PackageSetting ps, int[] allUserHandles,
+ private void removePackageDataLIF(PackageSetting ps, int[] allUserHandles,
PackageRemovedInfo outInfo, int flags, boolean writeSettings) {
String packageName = ps.name;
if (DEBUG_REMOVE) Slog.d(TAG, "removePackageDataLI: " + ps);
@@ -15075,7 +15088,7 @@
}
}
if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
- removeDataDirsLI(ps.volumeUuid, packageName);
+ removeDataDirsLIF(ps.volumeUuid, ps.name);
if (outInfo != null) {
outInfo.dataRemoved = true;
}
@@ -15160,7 +15173,7 @@
/*
* Tries to delete system package.
*/
- private boolean deleteSystemPackageLI(PackageParser.Package deletedPkg,
+ private boolean deleteSystemPackageLIF(PackageParser.Package deletedPkg,
PackageSetting deletedPs, int[] allUserHandles, int flags, PackageRemovedInfo outInfo,
boolean writeSettings) {
if (deletedPs.parentPackageName != null) {
@@ -15225,7 +15238,7 @@
flags |= PackageManager.DELETE_KEEP_DATA;
}
- boolean ret = deleteInstalledPackageLI(deletedPs, true, flags, allUserHandles,
+ boolean ret = deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles,
outInfo, writeSettings, disabledPs.pkg);
if (!ret) {
return false;
@@ -15293,7 +15306,7 @@
return true;
}
- private boolean deleteInstalledPackageLI(PackageSetting ps,
+ private boolean deleteInstalledPackageLIF(PackageSetting ps,
boolean deleteCodeAndResources, int flags, int[] allUserHandles,
PackageRemovedInfo outInfo, boolean writeSettings,
PackageParser.Package replacingPackage) {
@@ -15321,7 +15334,7 @@
}
// Delete package data from internal structures and also remove data if flag is set
- removePackageDataLI(ps, allUserHandles, outInfo, flags, writeSettings);
+ removePackageDataLIF(ps, allUserHandles, outInfo, flags, writeSettings);
// Delete the child packages data
final int childCount = (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
@@ -15338,7 +15351,7 @@
&& (replacingPackage != null
&& !replacingPackage.hasChildPackage(childPs.name))
? flags & ~DELETE_KEEP_DATA : flags;
- removePackageDataLI(childPs, allUserHandles, childOutInfo,
+ removePackageDataLIF(childPs, allUserHandles, childOutInfo,
deleteFlags, writeSettings);
}
}
@@ -15415,7 +15428,7 @@
/*
* This method handles package deletion in general
*/
- private boolean deletePackageLI(String packageName, UserHandle user,
+ private boolean deletePackageLIF(String packageName, UserHandle user,
boolean deleteCodeAndResources, int[] allUserHandles, int flags,
PackageRemovedInfo outInfo, boolean writeSettings,
PackageParser.Package replacingPackage) {
@@ -15443,7 +15456,7 @@
}
final int removedUserId = (user != null) ? user.getIdentifier()
: UserHandle.USER_ALL;
- if (!clearPackageStateForUser(ps, removedUserId, outInfo)) {
+ if (!clearPackageStateForUserLIF(ps, removedUserId, outInfo)) {
return false;
}
markPackageUninstalledForUserLPw(ps, user);
@@ -15469,7 +15482,7 @@
// we need to do is clear this user's data and save that
// it is uninstalled.
if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");
- if (!clearPackageStateForUser(ps, user.getIdentifier(), outInfo)) {
+ if (!clearPackageStateForUserLIF(ps, user.getIdentifier(), outInfo)) {
return false;
}
scheduleWritePackageRestrictionsLocked(user);
@@ -15486,7 +15499,7 @@
// we need to do is clear this user's data and save that
// it is uninstalled.
if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app");
- if (!clearPackageStateForUser(ps, user.getIdentifier(), outInfo)) {
+ if (!clearPackageStateForUserLIF(ps, user.getIdentifier(), outInfo)) {
return false;
}
scheduleWritePackageRestrictionsLocked(user);
@@ -15518,15 +15531,10 @@
if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package: " + ps.name);
// When an updated system application is deleted we delete the existing resources
// as well and fall back to existing code in system partition
- ret = deleteSystemPackageLI(ps.pkg, ps, allUserHandles, flags, outInfo, writeSettings);
+ ret = deleteSystemPackageLIF(ps.pkg, ps, allUserHandles, flags, outInfo, writeSettings);
} else {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
- // Kill application pre-emptively especially for apps on sd.
- final boolean killApp = (flags & PackageManager.DELETE_DONT_KILL_APP) == 0;
- if (killApp) {
- killApplication(packageName, ps.appId, "uninstall pkg");
- }
- ret = deleteInstalledPackageLI(ps, deleteCodeAndResources, flags, allUserHandles,
+ ret = deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,
outInfo, writeSettings, replacingPackage);
}
@@ -15594,7 +15602,7 @@
}
}
- private boolean clearPackageStateForUser(PackageSetting ps, int userId,
+ private boolean clearPackageStateForUserLIF(PackageSetting ps, int userId,
PackageRemovedInfo outInfo) {
final int[] userIds = (userId == UserHandle.USER_ALL) ? sUserManager.getUserIds()
: new int[] {userId};
@@ -15705,10 +15713,15 @@
@Override
public void clearApplicationProfileData(String packageName) {
enforceSystemOrRoot("Only the system can clear all profile data");
- try {
- mInstaller.clearAppProfiles(packageName);
- } catch (InstallerException ex) {
- Log.e(TAG, "Could not clear profile data of package " + packageName);
+ synchronized (mInstallLock) {
+ try (PackageFreezer freezer = freezePackage(packageName,
+ "clearApplicationProfileData")) {
+ try {
+ mInstaller.clearAppProfiles(packageName);
+ } catch (InstallerException ex) {
+ Log.e(TAG, "Could not clear profile data of package " + packageName);
+ }
+ }
}
}
@@ -15732,7 +15745,10 @@
mHandler.removeCallbacks(this);
final boolean succeeded;
synchronized (mInstallLock) {
- succeeded = clearApplicationUserDataLI(packageName, userId);
+ try (PackageFreezer freezer = freezePackage(packageName,
+ "clearApplicationUserData")) {
+ succeeded = clearApplicationUserDataLIF(packageName, userId);
+ }
}
clearExternalStorageDataSync(packageName, userId, true);
if (succeeded) {
@@ -15754,7 +15770,7 @@
});
}
- private boolean clearApplicationUserDataLI(String packageName, int userId) {
+ private boolean clearApplicationUserDataLIF(String packageName, int userId) {
if (packageName == null) {
Slog.w(TAG, "Attempt to delete null packageName.");
return false;
@@ -17446,6 +17462,7 @@
public static final int DUMP_INSTALLS = 1 << 16;
public static final int DUMP_INTENT_FILTER_VERIFIERS = 1 << 17;
public static final int DUMP_DOMAIN_PREFERRED = 1 << 18;
+ public static final int DUMP_FROZEN = 1 << 19;
public static final int OPTION_SHOW_FILTERS = 1 << 0;
@@ -17679,6 +17696,8 @@
dumpState.setDump(DumpState.DUMP_KEYSETS);
} else if ("installs".equals(cmd)) {
dumpState.setDump(DumpState.DUMP_INSTALLS);
+ } else if ("frozen".equals(cmd)) {
+ dumpState.setDump(DumpState.DUMP_FROZEN);
} else if ("write".equals(cmd)) {
synchronized (mPackages) {
mSettings.writeLPr();
@@ -18017,6 +18036,25 @@
mInstallerService.dump(new IndentingPrintWriter(pw, " ", 120));
}
+ if (!checkin && dumpState.isDumping(DumpState.DUMP_FROZEN) && packageName == null) {
+ // XXX should handle packageName != null by dumping only install data that
+ // the given package is involved with.
+ if (dumpState.onTitlePrinted()) pw.println();
+
+ final IndentingPrintWriter ipw = new IndentingPrintWriter(pw, " ", 120);
+ ipw.println();
+ ipw.println("Frozen packages:");
+ ipw.increaseIndent();
+ if (mFrozenPackages.size() == 0) {
+ ipw.println("(none)");
+ } else {
+ for (int i = 0; i < mFrozenPackages.size(); i++) {
+ ipw.println(mFrozenPackages.valueAt(i));
+ }
+ }
+ ipw.decreaseIndent();
+ }
+
if (!checkin && dumpState.isDumping(DumpState.DUMP_MESSAGES) && packageName == null) {
if (dumpState.onTitlePrinted()) pw.println();
mSettings.dumpReadMessagesLPr(pw, dumpState);
@@ -18329,7 +18367,9 @@
synchronized (mInstallLock) {
PackageParser.Package pkg = null;
try {
- pkg = scanPackageTracedLI(new File(codePath), parseFlags, 0, 0, null);
+ // Sadly we don't know the package name yet to freeze it
+ pkg = scanPackageTracedLI(new File(codePath), parseFlags,
+ SCAN_IGNORE_FROZEN, 0, null);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to scan " + codePath + ": " + e.getMessage());
}
@@ -18428,8 +18468,13 @@
// Delete package internally
PackageRemovedInfo outInfo = new PackageRemovedInfo();
synchronized (mInstallLock) {
- boolean res = deletePackageLI(pkgName, null, false, null,
- PackageManager.DELETE_KEEP_DATA, outInfo, false, null);
+ final int deleteFlags = PackageManager.DELETE_KEEP_DATA;
+ final boolean res;
+ try (PackageFreezer freezer = freezePackageForDelete(pkgName, deleteFlags,
+ "unloadMediaPackages")) {
+ res = deletePackageLIF(pkgName, null, false, null, deleteFlags, outInfo, false,
+ null);
+ }
if (res) {
pkgList.add(pkgName);
} else {
@@ -18484,6 +18529,7 @@
return;
}
+ final ArrayList<PackageFreezer> freezers = new ArrayList<>();
final ArrayList<ApplicationInfo> loaded = new ArrayList<>();
final int parseFlags = mDefParseFlags | PackageParser.PARSE_EXTERNAL_STORAGE;
@@ -18494,9 +18540,8 @@
packages = mSettings.getVolumePackagesLPr(volumeUuid);
}
- // TODO: introduce a new concept similar to "frozen" to prevent these
- // apps from being launched until after data has been fully reconciled
for (PackageSetting ps : packages) {
+ freezers.add(freezePackage(ps.name, "loadPrivatePackagesInner"));
synchronized (mInstallLock) {
final PackageParser.Package pkg;
try {
@@ -18508,7 +18553,7 @@
}
if (!Build.FINGERPRINT.equals(ver.fingerprint)) {
- deleteCodeCacheDirsLI(ps.volumeUuid, ps.name);
+ deleteCodeCacheDirsLIF(ps.volumeUuid, ps.name);
}
}
}
@@ -18545,6 +18590,10 @@
mSettings.writeLPr();
}
+ for (PackageFreezer freezer : freezers) {
+ freezer.close();
+ }
+
if (DEBUG_INSTALL) Slog.d(TAG, "Loaded packages " + loaded);
sendResourcesChangedBroadcast(true, false, loaded, null);
}
@@ -18573,12 +18622,17 @@
if (ps.pkg == null) continue;
final ApplicationInfo info = ps.pkg.applicationInfo;
+ final int deleteFlags = PackageManager.DELETE_KEEP_DATA;
final PackageRemovedInfo outInfo = new PackageRemovedInfo();
- if (deletePackageLI(ps.name, null, false, null,
- PackageManager.DELETE_KEEP_DATA, outInfo, false, null)) {
- unloaded.add(info);
- } else {
- Slog.w(TAG, "Failed to unload " + ps.codePath);
+
+ try (PackageFreezer freezer = freezePackageForDelete(ps.name, deleteFlags,
+ "unloadPrivatePackagesInner")) {
+ if (deletePackageLIF(ps.name, null, false, null, deleteFlags, outInfo,
+ false, null)) {
+ unloaded.add(info);
+ } else {
+ Slog.w(TAG, "Failed to unload " + ps.codePath);
+ }
}
}
@@ -18951,11 +19005,116 @@
}
}
- private void unfreezePackage(String packageName) {
+ public PackageFreezer freezePackage(String packageName, String killReason) {
+ return new PackageFreezer(packageName, killReason);
+ }
+
+ public PackageFreezer freezePackageForInstall(String packageName, int installFlags,
+ String killReason) {
+ if ((installFlags & PackageManager.INSTALL_DONT_KILL_APP) != 0) {
+ return new PackageFreezer();
+ } else {
+ return freezePackage(packageName, killReason);
+ }
+ }
+
+ public PackageFreezer freezePackageForDelete(String packageName, int deleteFlags,
+ String killReason) {
+ if ((deleteFlags & PackageManager.DELETE_DONT_KILL_APP) != 0) {
+ return new PackageFreezer();
+ } else {
+ return freezePackage(packageName, killReason);
+ }
+ }
+
+ /**
+ * Class that freezes and kills the given package upon creation, and
+ * unfreezes it upon closing. This is typically used when doing surgery on
+ * app code/data to prevent the app from running while you're working.
+ */
+ private class PackageFreezer implements AutoCloseable {
+ private final String mPackageName;
+ private final PackageFreezer[] mChildren;
+
+ private final boolean mWeFroze;
+
+ private final AtomicBoolean mClosed = new AtomicBoolean();
+ private final CloseGuard mCloseGuard = CloseGuard.get();
+
+ /**
+ * Create and return a stub freezer that doesn't actually do anything,
+ * typically used when someone requested
+ * {@link PackageManager#INSTALL_DONT_KILL_APP} or
+ * {@link PackageManager#DELETE_DONT_KILL_APP}.
+ */
+ public PackageFreezer() {
+ mPackageName = null;
+ mChildren = null;
+ mWeFroze = false;
+ mCloseGuard.open("close");
+ }
+
+ public PackageFreezer(String packageName, String killReason) {
+ synchronized (mPackages) {
+ mPackageName = packageName;
+ mWeFroze = mFrozenPackages.add(mPackageName);
+
+ final PackageSetting ps = mSettings.mPackages.get(mPackageName);
+ if (ps != null) {
+ killApplication(ps.name, ps.appId, killReason);
+ }
+
+ final PackageParser.Package p = mPackages.get(packageName);
+ if (p != null && p.childPackages != null) {
+ final int N = p.childPackages.size();
+ mChildren = new PackageFreezer[N];
+ for (int i = 0; i < N; i++) {
+ mChildren[i] = new PackageFreezer(p.childPackages.get(i).packageName,
+ killReason);
+ }
+ } else {
+ mChildren = null;
+ }
+ }
+ mCloseGuard.open("close");
+ }
+
+ @Override
+ protected void finalize() throws Throwable {
+ try {
+ mCloseGuard.warnIfOpen();
+ close();
+ } finally {
+ super.finalize();
+ }
+ }
+
+ @Override
+ public void close() {
+ mCloseGuard.close();
+ if (mClosed.compareAndSet(false, true)) {
+ synchronized (mPackages) {
+ if (mWeFroze) {
+ mFrozenPackages.remove(mPackageName);
+ }
+
+ if (mChildren != null) {
+ for (PackageFreezer freezer : mChildren) {
+ freezer.close();
+ }
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Verify that given package is currently frozen.
+ */
+ private void checkPackageFrozen(String packageName) {
synchronized (mPackages) {
- final PackageSetting ps = mSettings.mPackages.get(packageName);
- if (ps != null) {
- ps.frozen = false;
+ if (!mFrozenPackages.contains(packageName)) {
+ Slog.wtf(TAG, "Expected " + packageName + " to be frozen!", new Throwable());
}
}
}
@@ -18995,6 +19154,7 @@
final String seinfo;
final String label;
final int targetSdkVersion;
+ final PackageFreezer freezer;
// reader
synchronized (mPackages) {
@@ -19036,11 +19196,10 @@
"Device admin cannot be moved");
}
- if (ps.frozen) {
+ if (mFrozenPackages.contains(packageName)) {
throw new PackageManagerException(MOVE_FAILED_OPERATION_PENDING,
"Failed to move already frozen package");
}
- ps.frozen = true;
codeFile = new File(pkg.codePath);
installerPackageName = ps.installerPackageName;
@@ -19049,14 +19208,7 @@
seinfo = pkg.applicationInfo.seinfo;
label = String.valueOf(pm.getApplicationLabel(pkg.applicationInfo));
targetSdkVersion = pkg.applicationInfo.targetSdkVersion;
- }
-
- // Now that we're guarded by frozen state, kill app during move
- final long token = Binder.clearCallingIdentity();
- try {
- killApplication(packageName, appId, "move pkg");
- } finally {
- Binder.restoreCallingIdentity(token);
+ freezer = new PackageFreezer(packageName, "movePackageInternal");
}
final Bundle extras = new Bundle();
@@ -19080,7 +19232,7 @@
final VolumeInfo volume = storage.findVolumeByUuid(volumeUuid);
if (volume == null || volume.getType() != VolumeInfo.TYPE_PRIVATE
|| !volume.isMountedWritable()) {
- unfreezePackage(packageName);
+ freezer.close();
throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
"Move location not mounted private volume");
}
@@ -19095,7 +19247,7 @@
final PackageStats stats = new PackageStats(null, -1);
synchronized (mInstaller) {
if (!getPackageSizeInfoLI(packageName, -1, stats)) {
- unfreezePackage(packageName);
+ freezer.close();
throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
"Failed to measure package size");
}
@@ -19113,7 +19265,7 @@
}
if (sizeBytes > storage.getStorageBytesUntilLow(measurePath)) {
- unfreezePackage(packageName);
+ freezer.close();
throw new PackageManagerException(MOVE_FAILED_INTERNAL_ERROR,
"Not enough free space to move");
}
@@ -19134,10 +19286,7 @@
+ PackageManager.installStatusToString(returnCode, msg));
installedLatch.countDown();
-
- // Regardless of success or failure of the move operation,
- // always unfreeze the package
- unfreezePackage(packageName);
+ freezer.close();
final int status = PackageManager.installStatusToPublicStatus(returnCode);
switch (status) {
diff --git a/services/core/java/com/android/server/pm/PackageSettingBase.java b/services/core/java/com/android/server/pm/PackageSettingBase.java
index 1434718..2a96562 100644
--- a/services/core/java/com/android/server/pm/PackageSettingBase.java
+++ b/services/core/java/com/android/server/pm/PackageSettingBase.java
@@ -114,12 +114,6 @@
int installStatus = PKG_INSTALL_COMPLETE;
/**
- * Non-persisted value indicating this package has been temporarily frozen,
- * usually during a critical section of the package update pipeline. The
- * platform will refuse to launch packages in a frozen state.
- */
- boolean frozen = false;
- /**
* Non-persisted value. During an "upgrade without restart", we need the set
* of all previous code paths so we can surgically add the new APKs to the
* active classloader. If at any point an application is upgraded with a
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 83cd978..8f7cd5e 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4325,10 +4325,6 @@
pw.print(Integer.toHexString(System.identityHashCode(ps)));
pw.println("):");
- if (ps.frozen) {
- pw.print(prefix); pw.println(" FROZEN!");
- }
-
if (ps.realName != null) {
pw.print(prefix); pw.print(" compat name=");
pw.println(ps.name);