diff options
| -rw-r--r-- | services/core/java/com/android/server/pm/PackageManagerService.java | 281 |
1 files changed, 206 insertions, 75 deletions
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 4ff4885db42e..529fcc400463 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -85,6 +85,8 @@ import static android.content.pm.PackageManager.PERMISSION_GRANTED; import static android.content.pm.PackageParser.PARSE_IS_PRIVILEGED; import static android.content.pm.PackageParser.isApkFile; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; +import static android.os.storage.StorageManager.FLAG_STORAGE_CE; +import static android.os.storage.StorageManager.FLAG_STORAGE_DE; import static android.system.OsConstants.O_CREAT; import static android.system.OsConstants.O_RDWR; @@ -19757,6 +19759,10 @@ public class PackageManagerService extends IPackageManager.Stub // writer synchronized (mPackages) { + // NOTE: The system package always needs to be enabled; even if it's for + // a compressed stub. If we don't, installing the system package fails + // during scan [scanning checks the disabled packages]. We will reverse + // this later, after we've "installed" the stub. // Reinstate the old system package enableSystemPackageLPw(disabledPs.pkg); // Remove any native libraries from the upgraded package. @@ -19765,23 +19771,38 @@ public class PackageManagerService extends IPackageManager.Stub // Install the system package if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs); + try { + installPackageFromSystemLIF(disabledPs.codePath, false /*isPrivileged*/, allUserHandles, + outInfo.origUsers, deletedPs.getPermissionsState(), writeSettings); + } catch (PackageManagerException e) { + Slog.w(TAG, "Failed to restore system package:" + deletedPkg.packageName + ": " + + e.getMessage()); + return false; + } finally { + if (disabledPs.pkg.isStub) { + mSettings.disableSystemPackageLPw(disabledPs.name, true /*replaced*/); + } + } + return true; + } + + /** + * Installs a package that's already on the system partition. + */ + private PackageParser.Package installPackageFromSystemLIF(@NonNull File codePath, + boolean isPrivileged, @Nullable int[] allUserHandles, @Nullable int[] origUserHandles, + @Nullable PermissionsState origPermissionState, boolean writeSettings) + throws PackageManagerException { int parseFlags = mDefParseFlags | PackageParser.PARSE_MUST_BE_APK | PackageParser.PARSE_IS_SYSTEM | PackageParser.PARSE_IS_SYSTEM_DIR; - if (locationIsPrivileged(disabledPs.codePath)) { + if (isPrivileged || locationIsPrivileged(codePath)) { parseFlags |= PackageParser.PARSE_IS_PRIVILEGED; } - final PackageParser.Package newPkg; - try { - newPkg = scanPackageTracedLI(disabledPs.codePath, parseFlags, 0 /* scanFlags */, - 0 /* currentTime */, null); - } catch (PackageManagerException e) { - Slog.w(TAG, "Failed to restore system package:" + deletedPkg.packageName + ": " - + e.getMessage()); - return false; - } + final PackageParser.Package newPkg = + scanPackageTracedLI(codePath, parseFlags, 0 /*scanFlags*/, 0 /*currentTime*/, null); try { // update shared libraries for the newly re-installed system package @@ -19799,17 +19820,21 @@ public class PackageManagerService extends IPackageManager.Stub // Propagate the permissions state as we do not want to drop on the floor // runtime permissions. The update permissions method below will take // care of removing obsolete permissions and grant install permissions. - ps.getPermissionsState().copyFrom(deletedPs.getPermissionsState()); + if (origPermissionState != null) { + ps.getPermissionsState().copyFrom(origPermissionState); + } updatePermissionsLPw(newPkg.packageName, newPkg, UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG); + final boolean applyUserRestrictions + = (allUserHandles != null) && (origUserHandles != null); if (applyUserRestrictions) { boolean installedStateChanged = false; if (DEBUG_REMOVE) { Slog.d(TAG, "Propagating install state across reinstall"); } for (int userId : allUserHandles) { - final boolean installed = ArrayUtils.contains(outInfo.origUsers, userId); + final boolean installed = ArrayUtils.contains(origUserHandles, userId); if (DEBUG_REMOVE) { Slog.d(TAG, " user " + userId + " => " + installed); } @@ -19832,7 +19857,7 @@ public class PackageManagerService extends IPackageManager.Stub mSettings.writeLPr(); } } - return true; + return newPkg; } private boolean deleteInstalledPackageLIF(PackageSetting ps, @@ -21765,77 +21790,183 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); } } - synchronized (mPackages) { - if (callingUid == Process.SHELL_UID - && (pkgSetting.pkgFlags & ApplicationInfo.FLAG_TEST_ONLY) == 0) { - // Shell can only change whole packages between ENABLED and DISABLED_USER states - // unless it is a test package. - int oldState = pkgSetting.getEnabled(userId); - if (className == null - && - (oldState == COMPONENT_ENABLED_STATE_DISABLED_USER - || oldState == COMPONENT_ENABLED_STATE_DEFAULT - || oldState == COMPONENT_ENABLED_STATE_ENABLED) - && - (newState == COMPONENT_ENABLED_STATE_DISABLED_USER - || newState == COMPONENT_ENABLED_STATE_DEFAULT - || newState == COMPONENT_ENABLED_STATE_ENABLED)) { - // ok - } else { - throw new SecurityException( - "Shell cannot change component state for " + packageName + "/" - + className + " to " + newState); - } + if (callingUid == Process.SHELL_UID + && (pkgSetting.pkgFlags & ApplicationInfo.FLAG_TEST_ONLY) == 0) { + // Shell can only change whole packages between ENABLED and DISABLED_USER states + // unless it is a test package. + int oldState = pkgSetting.getEnabled(userId); + if (className == null + && + (oldState == COMPONENT_ENABLED_STATE_DISABLED_USER + || oldState == COMPONENT_ENABLED_STATE_DEFAULT + || oldState == COMPONENT_ENABLED_STATE_ENABLED) + && + (newState == COMPONENT_ENABLED_STATE_DISABLED_USER + || newState == COMPONENT_ENABLED_STATE_DEFAULT + || newState == COMPONENT_ENABLED_STATE_ENABLED)) { + // ok + } else { + throw new SecurityException( + "Shell cannot change component state for " + packageName + "/" + + className + " to " + newState); } - if (className == null) { - // We're dealing with an application/package level state change - if (pkgSetting.getEnabled(userId) == newState) { - // Nothing to do + } + if (className == null) { + // We're dealing with an application/package level state change + if (pkgSetting.getEnabled(userId) == newState) { + // Nothing to do + return; + } + // If we're enabling a system stub, there's a little more work to do. + // Prior to enabling the package, we need to decompress the APK(s) to the + // data partition and then replace the version on the system partition. + final PackageParser.Package deletedPkg = pkgSetting.pkg; + final boolean isSystemStub = deletedPkg.isStub + && deletedPkg.isSystemApp(); + if (isSystemStub + && (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT + || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED)) { + final File codePath = decompressPackage(deletedPkg); + if (codePath == null) { + Slog.e(TAG, "couldn't decompress pkg: " + pkgSetting.name); return; } - if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT - || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { - // Don't care about who enables an app. - callingPackage = null; - } - pkgSetting.setEnabled(newState, userId, callingPackage); - // pkgSetting.pkg.mSetEnabled = newState; - } else { - // We're dealing with a component level state change - // First, verify that this is a valid class name. - PackageParser.Package pkg = pkgSetting.pkg; - if (pkg == null || !pkg.hasComponentClassName(className)) { - if (pkg != null && - pkg.applicationInfo.targetSdkVersion >= - Build.VERSION_CODES.JELLY_BEAN) { - throw new IllegalArgumentException("Component class " + className - + " does not exist in " + packageName); - } else { - Slog.w(TAG, "Failed setComponentEnabledSetting: component class " - + className + " does not exist in " + packageName); - } + // TODO remove direct parsing of the package object during internal cleanup + // of scan package + // We need to call parse directly here for no other reason than we need + // the new package in order to disable the old one [we use the information + // for some internal optimization to optionally create a new package setting + // object on replace]. However, we can't get the package from the scan + // because the scan modifies live structures and we need to remove the + // old [system] package from the system before a scan can be attempted. + // Once scan is indempotent we can remove this parse and use the package + // object we scanned, prior to adding it to package settings. + final PackageParser pp = new PackageParser(); + pp.setSeparateProcesses(mSeparateProcesses); + pp.setDisplayMetrics(mMetrics); + pp.setCallback(mPackageParserCallback); + final PackageParser.Package tmpPkg; + try { + final int parseFlags = mDefParseFlags + | PackageParser.PARSE_MUST_BE_APK + | PackageParser.PARSE_IS_SYSTEM + | PackageParser.PARSE_IS_SYSTEM_DIR; + tmpPkg = pp.parsePackage(codePath, parseFlags); + } catch (PackageParserException e) { + Slog.w(TAG, "Failed to parse compressed system package:" + pkgSetting.name, e); + return; } - switch (newState) { - case COMPONENT_ENABLED_STATE_ENABLED: - if (!pkgSetting.enableComponentLPw(className, userId)) { - return; - } - break; - case COMPONENT_ENABLED_STATE_DISABLED: - if (!pkgSetting.disableComponentLPw(className, userId)) { - return; - } - break; - case COMPONENT_ENABLED_STATE_DEFAULT: - if (!pkgSetting.restoreComponentLPw(className, userId)) { + synchronized (mInstallLock) { + // Disable the stub and remove any package entries + removePackageLI(deletedPkg, true); + synchronized (mPackages) { + disableSystemPackageLPw(deletedPkg, tmpPkg); + } + final PackageParser.Package newPkg; + try (PackageFreezer freezer = + freezePackage(deletedPkg.packageName, "setEnabledSetting")) { + final int parseFlags = mDefParseFlags | PackageParser.PARSE_CHATTY + | PackageParser.PARSE_ENFORCE_CODE; + newPkg = scanPackageTracedLI(codePath, parseFlags, 0 /*scanFlags*/, + 0 /*currentTime*/, null /*user*/); + prepareAppDataAfterInstallLIF(newPkg); + synchronized (mPackages) { + try { + updateSharedLibrariesLPr(newPkg, null); + } catch (PackageManagerException e) { + Slog.e(TAG, "updateAllSharedLibrariesLPw failed: ", e); + } + updatePermissionsLPw(newPkg.packageName, newPkg, + UPDATE_PERMISSIONS_ALL | UPDATE_PERMISSIONS_REPLACE_PKG); + mSettings.writeLPr(); + } + } catch (PackageManagerException e) { + // Whoops! Something went wrong; try to roll back to the stub + Slog.w(TAG, "Failed to install compressed system package:" + + pkgSetting.name, e); + // Remove the failed install + removeCodePathLI(codePath); + + // Install the system package + try (PackageFreezer freezer = + freezePackage(deletedPkg.packageName, "setEnabledSetting")) { + synchronized (mPackages) { + // NOTE: The system package always needs to be enabled; even + // if it's for a compressed stub. If we don't, installing the + // system package fails during scan [scanning checks the disabled + // packages]. We will reverse this later, after we've "installed" + // the stub. + // This leaves us in a fragile state; the stub should never be + // enabled, so, cross your fingers and hope nothing goes wrong + // until we can disable the package later. + enableSystemPackageLPw(deletedPkg); + } + installPackageFromSystemLIF(new File(deletedPkg.codePath), + false /*isPrivileged*/, null /*allUserHandles*/, + null /*origUserHandles*/, null /*origPermissionsState*/, + true /*writeSettings*/); + } catch (PackageManagerException pme) { + Slog.w(TAG, "Failed to restore system package:" + + deletedPkg.packageName, pme); + } finally { + synchronized (mPackages) { + mSettings.disableSystemPackageLPw( + deletedPkg.packageName, true /*replaced*/); + mSettings.writeLPr(); + } + } return; } - break; - default: - Slog.e(TAG, "Invalid new component state: " + newState); + clearAppDataLIF(newPkg, UserHandle.USER_ALL, FLAG_STORAGE_DE + | FLAG_STORAGE_CE | Installer.FLAG_CLEAR_CODE_CACHE_ONLY); + clearAppProfilesLIF(newPkg, UserHandle.USER_ALL); + mDexManager.notifyPackageUpdated(newPkg.packageName, + newPkg.baseCodePath, newPkg.splitCodePaths); + } + } + if (newState == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT + || newState == PackageManager.COMPONENT_ENABLED_STATE_ENABLED) { + // Don't care about who enables an app. + callingPackage = null; + } + pkgSetting.setEnabled(newState, userId, callingPackage); + } else { + // We're dealing with a component level state change + // First, verify that this is a valid class name. + PackageParser.Package pkg = pkgSetting.pkg; + if (pkg == null || !pkg.hasComponentClassName(className)) { + if (pkg != null && + pkg.applicationInfo.targetSdkVersion >= + Build.VERSION_CODES.JELLY_BEAN) { + throw new IllegalArgumentException("Component class " + className + + " does not exist in " + packageName); + } else { + Slog.w(TAG, "Failed setComponentEnabledSetting: component class " + + className + " does not exist in " + packageName); + } + } + switch (newState) { + case COMPONENT_ENABLED_STATE_ENABLED: + if (!pkgSetting.enableComponentLPw(className, userId)) { return; } + break; + case COMPONENT_ENABLED_STATE_DISABLED: + if (!pkgSetting.disableComponentLPw(className, userId)) { + return; + } + break; + case COMPONENT_ENABLED_STATE_DEFAULT: + if (!pkgSetting.restoreComponentLPw(className, userId)) { + return; + } + break; + default: + Slog.e(TAG, "Invalid new component state: " + newState); + return; } + } + synchronized (mPackages) { scheduleWritePackageRestrictionsLocked(userId); updateSequenceNumberLP(pkgSetting, new int[] { userId }); final long callingId = Binder.clearCallingIdentity(); |