Makes non-system app deletion fail-safe
This is the second in a series of app delete refactors that moves
detection of all failure cases outside of the actual delete action for
non-system apps (system apps still require a subsequent install of the
disabled app that can still fail).
Bug: 109941548
Test: install, uninstall still work
Change-Id: I8ee470fdb02f2ae9cea1da0f23f484242c47173b
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 14682f3..c708b0a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -53,7 +53,6 @@
import static android.content.pm.PackageManager.INSTALL_FAILED_INVALID_INSTALL_LOCATION;
import static android.content.pm.PackageManager.INSTALL_FAILED_MISSING_SHARED_LIBRARY;
import static android.content.pm.PackageManager.INSTALL_FAILED_PACKAGE_CHANGED;
-import static android.content.pm.PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE;
import static android.content.pm.PackageManager.INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
import static android.content.pm.PackageManager.INSTALL_FAILED_TEST_ONLY;
import static android.content.pm.PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
@@ -15191,8 +15190,11 @@
}
}
private static class ReconcileFailure extends PackageManagerException {
- public ReconcileFailure(String message) {
- super("Invalid reconcile request: " + message);
+ ReconcileFailure(String message) {
+ super("Reconcile failed: " + message);
+ }
+ ReconcileFailure(int reason, String message) {
+ super(reason, "Reconcile failed: " + message);
}
}
@@ -15211,10 +15213,12 @@
@PackageManager.InstallFlags
public final int installFlags;
public final InstallArgs installArgs;
+ public final DeletePackageAction deletePackageAction;
private ReconciledPackage(InstallArgs installArgs, PackageSetting pkgSetting,
UserHandle installForUser, PackageInstalledInfo installResult, int installFlags,
- String volumeUuid, PrepareResult prepareResult, ScanResult scanResult) {
+ String volumeUuid, PrepareResult prepareResult, ScanResult scanResult,
+ DeletePackageAction deletePackageAction) {
this.installArgs = installArgs;
this.pkgSetting = pkgSetting;
this.installForUser = installForUser;
@@ -15223,6 +15227,7 @@
this.volumeUuid = volumeUuid;
this.prepareResult = prepareResult;
this.scanResult = scanResult;
+ this.deletePackageAction = deletePackageAction;
}
}
@@ -15235,14 +15240,29 @@
final ScanResult scanResult = request.scannedPackages.get(installPackageName);
final InstallArgs installArgs = request.installArgs.get(installPackageName);
final PackageInstalledInfo res = request.installResults.get(installPackageName);
+ final PrepareResult prepareResult = request.preparedPackages.get(installPackageName);
if (scanResult == null || installArgs == null || res == null) {
throw new ReconcileFailure(
"inputs not balanced; missing argument for " + installPackageName);
}
+ final DeletePackageAction deletePackageAction;
+ if (prepareResult.replace) {
+ deletePackageAction = mayDeletePackageLocked(res.removedInfo,
+ prepareResult.originalPs, prepareResult.disabledPs,
+ prepareResult.childPackageSettings);
+ if (deletePackageAction == null) {
+ throw new ReconcileFailure(
+ PackageManager.INSTALL_FAILED_REPLACE_COULDNT_DELETE,
+ "May not delete " + installPackageName + " to replace");
+ }
+ } else {
+ deletePackageAction = null;
+ }
result.put(installPackageName,
new ReconciledPackage(installArgs, scanResult.pkgSetting, installArgs.getUser(),
res, installArgs.installFlags, installArgs.volumeUuid,
- request.preparedPackages.get(installPackageName), scanResult));
+ request.preparedPackages.get(installPackageName), scanResult,
+ deletePackageAction));
}
return result;
}
@@ -15314,29 +15334,29 @@
final boolean killApp = (scanRequest.scanFlags & SCAN_DONT_KILL_APP) == 0;
final int deleteFlags = PackageManager.DELETE_KEEP_DATA
| (killApp ? 0 : PackageManager.DELETE_DONT_KILL_APP);
- // First delete the existing package while retaining the data directory
- if (!deletePackageLIF(packageName, null, true, request.mAllUsers, deleteFlags,
- res.removedInfo, true, pkg)) {
- // If the existing package wasn't successfully deleted
- res.setError(INSTALL_FAILED_REPLACE_COULDNT_DELETE,
- "replaceNonSystemPackageLI");
- return false;
- } else {
- // Successfully deleted the old package; proceed with replace.
-
- // If deleted package lived in a container, give users a chance to
- // relinquish resources before killing.
- if (oldPackage.isForwardLocked() || isExternal(oldPackage)) {
- if (DEBUG_INSTALL) {
- Slog.i(TAG, "upgrading pkg " + oldPackage
- + " is ASEC-hosted -> UNAVAILABLE");
- }
- final int[] uidArray = new int[]{oldPackage.applicationInfo.uid};
- final ArrayList<String> pkgList = new ArrayList<>(1);
- pkgList.add(oldPackage.applicationInfo.packageName);
- sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
+ try {
+ executeDeletePackageLIF(reconciledPkg.deletePackageAction, packageName,
+ null, true, request.mAllUsers, deleteFlags, true, pkg);
+ } catch (SystemDeleteException e) {
+ if (Build.IS_ENG) {
+ throw new RuntimeException("Unexpected failure", e);
+ // ignore; not possible for non-system app
}
}
+ // Successfully deleted the old package; proceed with replace.
+
+ // If deleted package lived in a container, give users a chance to
+ // relinquish resources before killing.
+ if (oldPackage.isForwardLocked() || isExternal(oldPackage)) {
+ if (DEBUG_INSTALL) {
+ Slog.i(TAG, "upgrading pkg " + oldPackage
+ + " is ASEC-hosted -> UNAVAILABLE");
+ }
+ final int[] uidArray = new int[]{oldPackage.applicationInfo.uid};
+ final ArrayList<String> pkgList = new ArrayList<>(1);
+ pkgList.add(oldPackage.applicationInfo.packageName);
+ sendResourcesChangedBroadcast(false, true, pkgList, uidArray, null);
+ }
// Update the in-memory copy of the previous code paths.
PackageSetting ps1 = mSettings.mPackages.get(
@@ -15744,13 +15764,16 @@
@Nullable
public final String renamedPackage;
public final PackageFreezer freezer;
+ public final PackageSetting originalPs;
+ public final PackageSetting disabledPs;
+ public final PackageSetting[] childPackageSettings;
private PrepareResult(int installReason, String volumeUuid,
String installerPackageName, UserHandle user, boolean replace, int scanFlags,
int parseFlags, PackageParser.Package existingPackage,
PackageParser.Package packageToScan, boolean clearCodeCache, boolean system,
- String renamedPackage,
- PackageFreezer freezer) {
+ String renamedPackage, PackageFreezer freezer, PackageSetting originalPs,
+ PackageSetting disabledPs, PackageSetting[] childPackageSettings) {
this.installReason = installReason;
this.volumeUuid = volumeUuid;
this.installerPackageName = installerPackageName;
@@ -15764,6 +15787,9 @@
this.system = system;
this.renamedPackage = renamedPackage;
this.freezer = freezer;
+ this.originalPs = originalPs;
+ this.disabledPs = disabledPs;
+ this.childPackageSettings = childPackageSettings;
}
}
@@ -16267,7 +16293,9 @@
String targetVolumeUuid = volumeUuid;
int targetScanFlags = scanFlags;
int targetParseFlags = parseFlags;
-
+ final PackageSetting ps;
+ final PackageSetting disabledPs;
+ final PackageSetting[] childPackages;
if (replace) {
targetVolumeUuid = null;
if (pkg.applicationInfo.isStaticSharedLibrary()) {
@@ -16287,7 +16315,6 @@
final boolean isInstantApp = (scanFlags & SCAN_AS_INSTANT_APP) != 0;
final PackageParser.Package oldPackage;
- final PackageSetting ps;
final String pkgName11 = pkg.packageName;
final int[] allUsers;
final int[] installedUsers;
@@ -16314,6 +16341,7 @@
}
ps = mSettings.mPackages.get(pkgName11);
+ disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
// verify signatures are valid
final KeySetManagerService ksms = mSettings.mKeySetManagerService;
@@ -16410,49 +16438,52 @@
res.removedInfo.installReasons.put(userId, ps.getInstallReason(userId));
}
- final int childCount = (oldPackage.childPackages != null)
- ? oldPackage.childPackages.size() : 0;
- for (int i = 0; i < childCount; i++) {
- boolean childPackageUpdated = false;
- PackageParser.Package childPkg = oldPackage.childPackages.get(i);
- final PackageSetting childPs = mSettings.getPackageLPr(childPkg.packageName);
- if (res.addedChildPackages != null) {
- PackageInstalledInfo childRes = res.addedChildPackages.get(
- childPkg.packageName);
- if (childRes != null) {
- childRes.removedInfo.uid = childPkg.applicationInfo.uid;
- childRes.removedInfo.removedPackage = childPkg.packageName;
- if (childPs != null) {
- childRes.removedInfo.installerPackageName =
- childPs.installerPackageName;
- }
- childRes.removedInfo.isUpdate = true;
- childRes.removedInfo.installReasons = res.removedInfo.installReasons;
- childPackageUpdated = true;
- }
- }
- if (!childPackageUpdated) {
- PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this);
- childRemovedRes.removedPackage = childPkg.packageName;
- if (childPs != null) {
- childRemovedRes.installerPackageName = childPs.installerPackageName;
- }
- childRemovedRes.isUpdate = false;
- childRemovedRes.dataRemoved = true;
- synchronized (mPackages) {
- if (childPs != null) {
- childRemovedRes.origUsers = childPs.queryInstalledUsers(allUsers,
- true);
+ childPackages = mSettings.getChildSettingsLPr(ps);
+ if (childPackages != null) {
+ for (PackageSetting childPs : childPackages) {
+ boolean childPackageUpdated = false;
+ PackageParser.Package childPkg = (childPs == null) ? null : childPs.pkg;
+ if (res.addedChildPackages != null) {
+ PackageInstalledInfo childRes = res.addedChildPackages.get(
+ childPkg.packageName);
+ if (childRes != null) {
+ childRes.removedInfo.uid = childPkg.applicationInfo.uid;
+ childRes.removedInfo.removedPackage = childPkg.packageName;
+ if (childPs != null) {
+ childRes.removedInfo.installerPackageName =
+ childPs.installerPackageName;
+ }
+ childRes.removedInfo.isUpdate = true;
+ childRes.removedInfo.installReasons =
+ res.removedInfo.installReasons;
+ childPackageUpdated = true;
}
}
- if (res.removedInfo.removedChildPackages == null) {
- res.removedInfo.removedChildPackages = new ArrayMap<>();
+ if (!childPackageUpdated) {
+ PackageRemovedInfo childRemovedRes = new PackageRemovedInfo(this);
+ childRemovedRes.removedPackage = childPkg.packageName;
+ if (childPs != null) {
+ childRemovedRes.installerPackageName = childPs.installerPackageName;
+ }
+ childRemovedRes.isUpdate = false;
+ childRemovedRes.dataRemoved = true;
+ synchronized (mPackages) {
+ if (childPs != null) {
+ childRemovedRes.origUsers = childPs.queryInstalledUsers(
+ allUsers,
+ true);
+ }
+ }
+ if (res.removedInfo.removedChildPackages == null) {
+ res.removedInfo.removedChildPackages = new ArrayMap<>();
+ }
+ res.removedInfo.removedChildPackages.put(childPkg.packageName,
+ childRemovedRes);
}
- res.removedInfo.removedChildPackages.put(childPkg.packageName,
- childRemovedRes);
}
}
+
sysPkg = (isSystemApp(oldPackage));
if (sysPkg) {
// Set the system/privileged/oem/vendor/product flags as needed
@@ -16495,6 +16526,9 @@
}
} else { // new package install
+ ps = null;
+ childPackages = null;
+ disabledPs = null;
replace = false;
existingPackage = null;
// Remember this for later, in case we need to rollback this install
@@ -16525,9 +16559,11 @@
}
// we're passing the freezer back to be closed in a later phase of install
shouldCloseFreezerBeforeReturn = false;
+
return new PrepareResult(args.installReason, targetVolumeUuid, installerPackageName,
args.user, replace, targetScanFlags, targetParseFlags, existingPackage, pkg,
- replace /* clearCodeCache */, sysPkg, renamedPackage, freezer);
+ replace /* clearCodeCache */, sysPkg, renamedPackage, freezer,
+ ps, disabledPs, childPackages);
} finally {
if (shouldCloseFreezerBeforeReturn) {
freezer.close();
@@ -17477,34 +17513,20 @@
/*
* Tries to delete system package.
*/
- private boolean deleteSystemPackageLIF(PackageParser.Package deletedPkg,
- PackageSetting deletedPs, int[] allUserHandles, int flags, PackageRemovedInfo outInfo,
- boolean writeSettings) {
- if (deletedPs.parentPackageName != null) {
- Slog.w(TAG, "Attempt to delete child system package " + deletedPkg.packageName);
- return false;
- }
-
+ private void deleteSystemPackageLIF(DeletePackageAction action,
+ PackageParser.Package deletedPkg, PackageSetting deletedPs, int[] allUserHandles,
+ int flags, PackageRemovedInfo outInfo, boolean writeSettings)
+ throws SystemDeleteException {
final boolean applyUserRestrictions
= (allUserHandles != null) && (outInfo.origUsers != null);
- final PackageSetting disabledPs;
// Confirm if the system package has been updated
// An updated system app can be deleted. This will also have to restore
// the system pkg from system partition
// reader
- synchronized (mPackages) {
- disabledPs = mSettings.getDisabledSystemPkgLPr(deletedPs.name);
- }
-
+ final PackageSetting disabledPs = action.disabledPs;
if (DEBUG_REMOVE) Slog.d(TAG, "deleteSystemPackageLI: newPs=" + deletedPkg.packageName
+ " disabledPs=" + disabledPs);
-
- if (disabledPs == null) {
- Slog.w(TAG, "Attempt to delete unknown system package "+ deletedPkg.packageName);
- return false;
- } else if (DEBUG_REMOVE) {
- Slog.d(TAG, "Deleting system pkg from data partition");
- }
+ Slog.d(TAG, "Deleting system pkg from data partition");
if (DEBUG_REMOVE) {
if (applyUserRestrictions) {
@@ -17542,11 +17564,8 @@
flags |= PackageManager.DELETE_KEEP_DATA;
}
- boolean ret = deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles,
+ deleteInstalledPackageLIF(deletedPs, true, flags, allUserHandles,
outInfo, writeSettings, disabledPs.pkg);
- if (!ret) {
- return false;
- }
// writer
synchronized (mPackages) {
@@ -17563,25 +17582,25 @@
// Install the system package
if (DEBUG_REMOVE) Slog.d(TAG, "Re-installing system package: " + disabledPs);
try {
- installPackageFromSystemLIF(disabledPs.codePathString, false, allUserHandles,
+ installPackageFromSystemLIF(disabledPs.codePathString, allUserHandles,
outInfo.origUsers, deletedPs.getPermissionsState(), writeSettings);
} catch (PackageManagerException e) {
Slog.w(TAG, "Failed to restore system package:" + deletedPkg.packageName + ": "
+ e.getMessage());
- return false;
+ // TODO(patb): can we avoid this; throw would come from scan...
+ throw new SystemDeleteException(e);
} 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 String codePathString,
- boolean isPrivileged, @Nullable int[] allUserHandles, @Nullable int[] origUserHandles,
+ @Nullable int[] allUserHandles, @Nullable int[] origUserHandles,
@Nullable PermissionsState origPermissionState, boolean writeSettings)
throws PackageManagerException {
@ParseFlags int parseFlags =
@@ -17589,7 +17608,7 @@
| PackageParser.PARSE_MUST_BE_APK
| PackageParser.PARSE_IS_SYSTEM_DIR;
@ScanFlags int scanFlags = SCAN_AS_SYSTEM;
- if (isPrivileged || locationIsPrivileged(codePathString)) {
+ if (locationIsPrivileged(codePathString)) {
scanFlags |= SCAN_AS_PRIVILEGED;
}
if (locationIsOem(codePathString)) {
@@ -17665,7 +17684,7 @@
return pkg;
}
- private boolean deleteInstalledPackageLIF(PackageSetting ps,
+ private void deleteInstalledPackageLIF(PackageSetting ps,
boolean deleteCodeAndResources, int flags, int[] allUserHandles,
PackageRemovedInfo outInfo, boolean writeSettings,
PackageParser.Package replacingPackage) {
@@ -17680,9 +17699,6 @@
for (int i = 0; i < childCount; i++) {
String childPackageName = ps.childPackageNames.get(i);
PackageSetting childPs = mSettings.mPackages.get(childPackageName);
- if (childPs == null) {
- return false;
- }
PackageRemovedInfo childInfo = outInfo.removedChildPackages.get(
childPackageName);
if (childInfo != null) {
@@ -17723,8 +17739,6 @@
if (DEBUG_SD_INSTALL) Slog.i(TAG, "args=" + outInfo.args);
}
}
-
- return true;
}
@Override
@@ -17780,26 +17794,59 @@
private static class DeletePackageAction {
public final PackageSetting deletingPs;
+ public final PackageSetting disabledPs;
+ public final PackageRemovedInfo outInfo;
- private DeletePackageAction(PackageSetting deletingPs) {
+ private DeletePackageAction(PackageSetting deletingPs, PackageSetting disabledPs,
+ PackageRemovedInfo outInfo) {
this.deletingPs = deletingPs;
+ this.disabledPs = disabledPs;
+ this.outInfo = outInfo;
}
}
/**
- * @return a {@link DeletePackageAction} if the provided package may be deleted, {@code null}
- * otherwise.
+ * @return a {@link DeletePackageAction} if the provided package and related state may be
+ * deleted, {@code null} otherwise.
*/
@Nullable
- private DeletePackageAction mayDeletePackageLIF(@NonNull String packageName) {
- synchronized (mPackages) {
- final PackageSetting ps;
- ps = mSettings.mPackages.get(packageName);
- if (ps == null) {
+ @GuardedBy("mPackages")
+ private static DeletePackageAction mayDeletePackageLocked(
+ PackageRemovedInfo outInfo, PackageSetting ps, @Nullable PackageSetting disabledPs,
+ @Nullable PackageSetting[] children) {
+ if (ps == null) {
+ return null;
+ }
+ if (isSystemApp(ps)) {
+ if (ps.parentPackageName == null) {
+ Slog.w(TAG, "Attempt to delete child system package " + ps.pkg.packageName);
return null;
}
- return new DeletePackageAction(ps);
+
+ // Confirm if the system package has been updated
+ // An updated system app can be deleted. This will also have to restore
+ // the system pkg from system partition
+ // reader
+ if (disabledPs == null) {
+ Slog.w(TAG,
+ "Attempt to delete unknown system package " + ps.pkg.packageName);
+ return null;
+ }
}
+ final int parentReferenceCount =
+ (ps.childPackageNames != null) ? ps.childPackageNames.size() : 0;
+ final int childCount = children != null ? children.length : 0;
+ if (childCount != parentReferenceCount) {
+ return null;
+ }
+ if (childCount != 0 && outInfo != null && outInfo.removedChildPackages != null) {
+ for (PackageSetting child : children) {
+ if (child == null || !ps.childPackageNames.contains(child.name)) {
+ return null;
+ }
+ }
+ }
+ return new DeletePackageAction(ps, disabledPs, outInfo);
}
/*
@@ -17809,22 +17856,43 @@
boolean deleteCodeAndResources, int[] allUserHandles, int flags,
PackageRemovedInfo outInfo, boolean writeSettings,
PackageParser.Package replacingPackage) {
- final DeletePackageAction action = mayDeletePackageLIF(packageName);
+ final DeletePackageAction action;
+ synchronized (mPackages) {
+ final PackageSetting ps = mSettings.mPackages.get(packageName);
+ final PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(ps);
+ PackageSetting[] children = mSettings.getChildSettingsLPr(ps);
+ action = mayDeletePackageLocked(outInfo, ps, disabledPs, children);
+ }
if (null == action) {
return false;
}
if (DEBUG_REMOVE) Slog.d(TAG, "deletePackageLI: " + packageName + " user " + user);
- return executeDeletePackageLIF(action, packageName, user, deleteCodeAndResources,
- allUserHandles, flags, outInfo, writeSettings, replacingPackage);
+ try {
+ executeDeletePackageLIF(action, packageName, user, deleteCodeAndResources,
+ allUserHandles, flags, writeSettings, replacingPackage);
+ } catch (SystemDeleteException e) {
+ return false;
+ }
+ return true;
}
- private boolean executeDeletePackageLIF(DeletePackageAction action,
+ private static class SystemDeleteException extends Exception {
+ public final PackageManagerException reason;
+
+ private SystemDeleteException(PackageManagerException reason) {
+ this.reason = reason;
+ }
+ }
+
+ /** Deletes a package. Only throws when install of a disabled package fails. */
+ private void executeDeletePackageLIF(DeletePackageAction action,
String packageName, UserHandle user, boolean deleteCodeAndResources,
- int[] allUserHandles, int flags, PackageRemovedInfo outInfo,
- boolean writeSettings, PackageParser.Package replacingPackage) {
+ int[] allUserHandles, int flags, boolean writeSettings,
+ PackageParser.Package replacingPackage) throws SystemDeleteException {
final PackageSetting ps = action.deletingPs;
+ final PackageRemovedInfo outInfo = action.outInfo;
final boolean systemApp = isSystemApp(ps);
synchronized (mPackages) {
@@ -17840,7 +17908,7 @@
clearPackageStateForUserLIF(ps, removedUserId, outInfo);
markPackageUninstalledForUserLPw(ps, user);
scheduleWritePackageRestrictionsLocked(user);
- return true;
+ return;
}
}
@@ -17869,7 +17937,7 @@
if (DEBUG_REMOVE) Slog.d(TAG, "Still installed by other users");
clearPackageStateForUserLIF(ps, user.getIdentifier(), outInfo);
scheduleWritePackageRestrictionsLocked(user);
- return true;
+ return;
} else {
// We need to set it back to 'installed' so the uninstall
// broadcasts will be sent correctly.
@@ -17885,7 +17953,7 @@
if (DEBUG_REMOVE) Slog.d(TAG, "Deleting system app");
clearPackageStateForUserLIF(ps, user.getIdentifier(), outInfo);
scheduleWritePackageRestrictionsLocked(user);
- return true;
+ return;
}
}
@@ -17910,15 +17978,15 @@
}
// TODO(b/109941548): break reasons for ret = false out into mayDelete method
- final boolean ret;
if (systemApp) {
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 = deleteSystemPackageLIF(ps.pkg, ps, allUserHandles, flags, outInfo, writeSettings);
+ deleteSystemPackageLIF(
+ action, ps.pkg, ps, allUserHandles, flags, outInfo, writeSettings);
} else {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing non-system package: " + ps.name);
- ret = deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,
+ deleteInstalledPackageLIF(ps, deleteCodeAndResources, flags, allUserHandles,
outInfo, writeSettings, replacingPackage);
}
@@ -17967,8 +18035,6 @@
}
}
}
-
- return ret;
}
@GuardedBy("mPackages")
@@ -19694,7 +19760,7 @@
enableSystemPackageLPw(deletedPkg);
}
installPackageFromSystemLIF(deletedPkg.codePath,
- false /*isPrivileged*/, null /*allUserHandles*/,
+ /*isPrivileged*/ null /*allUserHandles*/,
null /*origUserHandles*/, null /*origPermissionsState*/,
true /*writeSettings*/);
} catch (PackageManagerException pme) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 9e5a4c6..c524dba 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4255,11 +4255,48 @@
return false;
}
+ /**
+ * Returns the disabled {@link PackageSetting} for the provided package name if one exists,
+ * {@code null} otherwise.
+ */
+ @Nullable
public PackageSetting getDisabledSystemPkgLPr(String name) {
PackageSetting ps = mDisabledSysPackages.get(name);
return ps;
}
+ /**
+ * Returns the disabled {@link PackageSetting} for the provided enabled {@link PackageSetting}
+ * if one exists, {@code null} otherwise.
+ */
+ @Nullable
+ public PackageSetting getDisabledSystemPkgLPr(PackageSetting enabledPackageSetting) {
+ if (enabledPackageSetting == null) {
+ return null;
+ }
+ return getDisabledSystemPkgLPr(enabledPackageSetting.name);
+ }
+
+ /**
+ * Fetches an array of the child {@link PackageSetting}s for all child package names referenced
+ * by the provided parent {@link PackageSetting} or {@code null} if no children are referenced.
+ *
+ * Note: Any child packages not found will be null in the returned array.
+ */
+ @Nullable
+ public PackageSetting[] getChildSettingsLPr(PackageSetting parentPackageSetting) {
+ if (parentPackageSetting == null || !parentPackageSetting.hasChildPackages()) {
+ return null;
+ }
+ final int childCount = parentPackageSetting.childPackageNames.size();
+ PackageSetting[] children =
+ new PackageSetting[childCount];
+ for (int i = 0; i < childCount; i++) {
+ children[i] = mPackages.get(parentPackageSetting.childPackageNames.get(i));
+ }
+ return children;
+ }
+
boolean isEnabledAndMatchLPr(ComponentInfo componentInfo, int flags, int userId) {
final PackageSetting ps = mPackages.get(componentInfo.packageName);
if (ps == null) return false;