diff options
10 files changed, 208 insertions, 52 deletions
diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index c5c39f82a1fd..6e4d19f8d277 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -86,6 +86,7 @@ import static com.android.server.pm.PackageManagerServiceUtils.compareSignatures import static com.android.server.pm.PackageManagerServiceUtils.compressedFileExists; import static com.android.server.pm.PackageManagerServiceUtils.deriveAbiOverride; import static com.android.server.pm.PackageManagerServiceUtils.logCriticalInfo; +import static com.android.server.pm.SharedUidMigration.BEST_EFFORT; import android.annotation.NonNull; import android.annotation.Nullable; @@ -287,6 +288,12 @@ final class InstallPackageHelper { SharedUserSetting sharedUserSetting = mPm.mSettings.getSharedUserSettingLPr(pkgSetting); if (sharedUserSetting != null) { sharedUserSetting.addPackage(pkgSetting); + if (parsedPackage.isLeavingSharedUid() + && SharedUidMigration.applyStrategy(BEST_EFFORT) + && sharedUserSetting.isSingleUser()) { + // Attempt the transparent shared UID migration + mPm.mSettings.convertSharedUserSettingsLPw(sharedUserSetting); + } } if (reconciledPkg.mInstallArgs != null && reconciledPkg.mInstallArgs.mForceQueryableOverride) { @@ -2216,23 +2223,8 @@ final class InstallPackageHelper { } incrementalStorages.add(storage); } - int previousAppId = 0; - if (reconciledPkg.mScanResult.needsNewAppId()) { - // Only set previousAppId if the app is migrating out of shared UID - previousAppId = reconciledPkg.mScanResult.mPreviousAppId; - - if (pkg.shouldInheritKeyStoreKeys()) { - // Migrate keystore data - mAppDataHelper.migrateKeyStoreData( - previousAppId, reconciledPkg.mPkgSetting.getAppId()); - } - - if (reconciledPkg.mInstallResult.mRemovedInfo.mRemovedAppId == previousAppId) { - // If the previous app ID is removed, clear the keys - mAppDataHelper.clearKeystoreData(UserHandle.USER_ALL, previousAppId); - } - } - mAppDataHelper.prepareAppDataPostCommitLIF(pkg, previousAppId); + // Hardcode previousAppId to 0 to disable any data migration (http://b/221088088) + mAppDataHelper.prepareAppDataPostCommitLIF(pkg, 0); if (reconciledPkg.mPrepareResult.mClearCodeCache) { mAppDataHelper.clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE | FLAG_STORAGE_EXTERNAL @@ -3026,8 +3018,7 @@ final class InstallPackageHelper { installPackageFromSystemLIF(stubPkg.getPath(), mPm.mUserManager.getUserIds() /*allUserHandles*/, null /*origUserHandles*/, - true /*writeSettings*/, - Process.INVALID_UID /*previousAppId*/); + true /*writeSettings*/); } catch (PackageManagerException pme) { // Serious WTF; we have to be able to install the stub Slog.wtf(TAG, "Failed to restore system package:" + stubPkg.getPackageName(), @@ -3154,10 +3145,8 @@ final class InstallPackageHelper { try { synchronized (mPm.mInstallLock) { final int[] origUsers = outInfo == null ? null : outInfo.mOrigUsers; - final int previousAppId = disabledPs.getAppId() != deletedPs.getAppId() - ? deletedPs.getAppId() : Process.INVALID_UID; installPackageFromSystemLIF(disabledPs.getPathString(), allUserHandles, - origUsers, writeSettings, previousAppId); + origUsers, writeSettings); } } catch (PackageManagerException e) { Slog.w(TAG, "Failed to restore system package:" + deletedPs.getPackageName() + ": " @@ -3200,7 +3189,7 @@ final class InstallPackageHelper { @GuardedBy("mPm.mInstallLock") private void installPackageFromSystemLIF(@NonNull String codePathString, @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, - boolean writeSettings, int previousAppId) + boolean writeSettings) throws PackageManagerException { final File codePath = new File(codePathString); @ParsingPackageUtils.ParseFlags int parseFlags = @@ -3223,13 +3212,12 @@ final class InstallPackageHelper { mAppDataHelper.prepareAppDataAfterInstallLIF(pkg); - setPackageInstalledForSystemPackage(pkg, allUserHandles, - origUserHandles, writeSettings, previousAppId); + setPackageInstalledForSystemPackage(pkg, allUserHandles, origUserHandles, writeSettings); } private void setPackageInstalledForSystemPackage(@NonNull AndroidPackage pkg, @NonNull int[] allUserHandles, @Nullable int[] origUserHandles, - boolean writeSettings, int previousAppId) { + boolean writeSettings) { // writer synchronized (mPm.mLock) { PackageSetting ps = mPm.mSettings.getPackageLPr(pkg.getPackageName()); @@ -3263,7 +3251,7 @@ final class InstallPackageHelper { // The method below will take care of removing obsolete permissions and granting // install permissions. - mPm.mPermissionManager.onPackageInstalled(pkg, previousAppId, + mPm.mPermissionManager.onPackageInstalled(pkg, Process.INVALID_UID, PermissionManagerServiceInternal.PackageInstalledParams.DEFAULT, UserHandle.USER_ALL); for (final int userId : allUserHandles) { @@ -3701,7 +3689,14 @@ final class InstallPackageHelper { } disabledPkgSetting = mPm.mSettings.getDisabledSystemPkgLPr( parsedPackage.getPackageName()); - if (parsedPackage.getSharedUserId() != null && !parsedPackage.isLeavingSharedUid()) { + + boolean ignoreSharedUserId = false; + if (installedPkgSetting == null) { + // We can directly ignore sharedUserSetting for new installs + ignoreSharedUserId = parsedPackage.isLeavingSharedUid(); + } + + if (!ignoreSharedUserId && parsedPackage.getSharedUserId() != null) { sharedUserSetting = mPm.mSettings.getSharedUserLPw( parsedPackage.getSharedUserId(), 0 /*pkgFlags*/, 0 /*pkgPrivateFlags*/, true /*create*/); diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java index 742cc0237cec..6a80852f1bf5 100644 --- a/services/core/java/com/android/server/pm/Installer.java +++ b/services/core/java/com/android/server/pm/Installer.java @@ -215,6 +215,8 @@ public class Installer extends SystemService { if (!checkBeforeRemote()) { return buildPlaceholderCreateAppDataResult(); } + // Hardcode previousAppId to 0 to disable any data migration (http://b/221088088) + args.previousAppId = 0; try { return mInstalld.createAppData(args); } catch (Exception e) { @@ -229,6 +231,10 @@ public class Installer extends SystemService { Arrays.fill(results, buildPlaceholderCreateAppDataResult()); return results; } + // Hardcode previousAppId to 0 to disable any data migration (http://b/221088088) + for (final CreateAppDataArgs arg : args) { + arg.previousAppId = 0; + } try { return mInstalld.createAppDataBatched(args); } catch (Exception e) { diff --git a/services/core/java/com/android/server/pm/PackageSetting.java b/services/core/java/com/android/server/pm/PackageSetting.java index f06ae1e06187..2bae00f91b82 100644 --- a/services/core/java/com/android/server/pm/PackageSetting.java +++ b/services/core/java/com/android/server/pm/PackageSetting.java @@ -477,6 +477,7 @@ public class PackageSetting extends SettingBase implements PackageStateInternal public void setSharedUserAppId(int sharedUserAppId) { mSharedUserAppId = sharedUserAppId; + onChanged(); } @Override diff --git a/services/core/java/com/android/server/pm/RemovePackageHelper.java b/services/core/java/com/android/server/pm/RemovePackageHelper.java index 4d1519c361c9..88df843ec8c5 100644 --- a/services/core/java/com/android/server/pm/RemovePackageHelper.java +++ b/services/core/java/com/android/server/pm/RemovePackageHelper.java @@ -284,7 +284,11 @@ final class RemovePackageHelper { List<AndroidPackage> sharedUserPkgs = sus != null ? sus.getPackages() : Collections.emptyList(); mPermissionManager.onPackageUninstalled(packageName, deletedPs.getAppId(), - deletedPs.getPkg(), sharedUserPkgs, UserHandle.USER_ALL); + deletedPkg, sharedUserPkgs, UserHandle.USER_ALL); + // After permissions are handled, check if the shared user can be migrated + if (sus != null) { + mPm.mSettings.checkAndConvertSharedUserSettingsLPw(sus); + } } mPm.clearPackagePreferredActivitiesLPw( deletedPs.getPackageName(), changedUsers, UserHandle.USER_ALL); diff --git a/services/core/java/com/android/server/pm/ScanPackageUtils.java b/services/core/java/com/android/server/pm/ScanPackageUtils.java index 33f0b54fb2de..4e8313bf1891 100644 --- a/services/core/java/com/android/server/pm/ScanPackageUtils.java +++ b/services/core/java/com/android/server/pm/ScanPackageUtils.java @@ -165,25 +165,15 @@ final class ScanPackageUtils { } } - int previousAppId = Process.INVALID_UID; - if (pkgSetting != null && oldSharedUserSetting != sharedUserSetting) { - if (oldSharedUserSetting != null && sharedUserSetting == null) { - previousAppId = pkgSetting.getAppId(); - // Log that something is leaving shareduid and keep going - Slog.i(TAG, - "Package " + parsedPackage.getPackageName() + " shared user changed from " - + oldSharedUserSetting.name + " to " + "<nothing>."); - } else { - PackageManagerService.reportSettingsProblem(Log.WARN, - "Package " + parsedPackage.getPackageName() + " shared user changed from " - + (oldSharedUserSetting != null - ? oldSharedUserSetting.name : "<nothing>") - + " to " - + (sharedUserSetting != null ? sharedUserSetting.name : "<nothing>") - + "; replacing with new"); - pkgSetting = null; - } + PackageManagerService.reportSettingsProblem(Log.WARN, + "Package " + parsedPackage.getPackageName() + " shared user changed from " + + (oldSharedUserSetting != null + ? oldSharedUserSetting.name : "<nothing>") + + " to " + + (sharedUserSetting != null ? sharedUserSetting.name : "<nothing>") + + "; replacing with new"); + pkgSetting = null; } String[] usesSdkLibraries = null; @@ -474,8 +464,8 @@ final class ScanPackageUtils { return new ScanResult(request, true, pkgSetting, changedAbiCodePath, !createNewPackage /* existingSettingCopied */, - previousAppId, sdkLibraryInfo, staticSharedLibraryInfo, - dynamicSharedLibraryInfos); + Process.INVALID_UID /* previousAppId */ , sdkLibraryInfo, + staticSharedLibraryInfo, dynamicSharedLibraryInfos); } /** diff --git a/services/core/java/com/android/server/pm/ScanResult.java b/services/core/java/com/android/server/pm/ScanResult.java index f77be1f9b2d3..e2860ca327e7 100644 --- a/services/core/java/com/android/server/pm/ScanResult.java +++ b/services/core/java/com/android/server/pm/ScanResult.java @@ -70,7 +70,9 @@ final class ScanResult { mPkgSetting = pkgSetting; mChangedAbiCodePath = changedAbiCodePath; mExistingSettingCopied = existingSettingCopied; - mPreviousAppId = previousAppId; + // Hardcode mPreviousAppId to INVALID_UID (http://b/221088088) + // This will disable all migration code paths in PMS and PermMS + mPreviousAppId = Process.INVALID_UID; mSdkSharedLibraryInfo = sdkSharedLibraryInfo; mStaticSharedLibraryInfo = staticSharedLibraryInfo; mDynamicSharedLibraryInfos = dynamicSharedLibraryInfos; diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java index d3665749a7f8..e6f23775f615 100644 --- a/services/core/java/com/android/server/pm/Settings.java +++ b/services/core/java/com/android/server/pm/Settings.java @@ -29,6 +29,7 @@ import static android.os.Process.PACKAGE_INFO_GID; import static android.os.Process.SYSTEM_UID; import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME; +import static com.android.server.pm.SharedUidMigration.BEST_EFFORT; import android.annotation.NonNull; import android.annotation.Nullable; @@ -1424,6 +1425,35 @@ public final class Settings implements Watchable, Snappable { } } + /** + * Transparently convert a SharedUserSetting into PackageSettings without changing appId. + * The sharedUser passed to this method has to be {@link SharedUserSetting#isSingleUser()}. + */ + void convertSharedUserSettingsLPw(SharedUserSetting sharedUser) { + final PackageSetting ps = sharedUser.getPackageSettings().valueAt(0); + replaceAppIdLPw(sharedUser.getAppId(), ps); + + // Unlink the SharedUserSetting + ps.setSharedUserAppId(INVALID_UID); + if (!sharedUser.getDisabledPackageSettings().isEmpty()) { + final PackageSetting disabledPs = sharedUser.getDisabledPackageSettings().valueAt(0); + disabledPs.setSharedUserAppId(INVALID_UID); + } + mSharedUsers.remove(sharedUser.getName()); + } + + /** + * Check and convert eligible SharedUserSettings to PackageSettings. + */ + void checkAndConvertSharedUserSettingsLPw(SharedUserSetting sharedUser) { + if (!sharedUser.isSingleUser()) return; + final AndroidPackage pkg = sharedUser.getPackageSettings().valueAt(0).getPkg(); + if (pkg != null && pkg.isLeavingSharedUid() + && SharedUidMigration.applyStrategy(BEST_EFFORT)) { + convertSharedUserSettingsLPw(sharedUser); + } + } + PreferredIntentResolver editPreferredActivitiesLPw(int userId) { PreferredIntentResolver pir = mPreferredActivities.get(userId); if (pir == null) { diff --git a/services/core/java/com/android/server/pm/SharedUidMigration.java b/services/core/java/com/android/server/pm/SharedUidMigration.java new file mode 100644 index 000000000000..a7d5e9550149 --- /dev/null +++ b/services/core/java/com/android/server/pm/SharedUidMigration.java @@ -0,0 +1,105 @@ +/* + * Copyright (C) 2022 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.pm; + +import android.annotation.IntDef; +import android.os.Build; +import android.os.SystemProperties; + +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; + +/** + * A utility class hosting code configuring shared UID migration behavior. + */ +public final class SharedUidMigration { + + /** + * The system property key used to configure the shared UID migration strategy. + */ + public static final String PROPERTY_KEY = "persist.debug.pm.shared_uid_migration_strategy"; + + /** + * Only leave shared UID for newly installed packages. + */ + public static final int NEW_INSTALL_ONLY = 1; + /** + * Opportunistically migrate any single-package shared UID group. + */ + public static final int BEST_EFFORT = 2; + /** + * Run appId transitions when the device reboots. + */ + public static final int TRANSITION_AT_BOOT = 3; + /** + * Run appId transitions as soon as the upgrade is installed. + */ + public static final int LIVE_TRANSITION = 4; + + @IntDef({ + NEW_INSTALL_ONLY, + BEST_EFFORT, + TRANSITION_AT_BOOT, + LIVE_TRANSITION, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface Strategy {} + + private static final int DEFAULT = BEST_EFFORT; + + /** + * All shared UID migration is disabled. + * This is not a strategy that can be set with system properties. + * To disable shared UID migration, change {@link #DEFAULT} to this value. + */ + private static final int DISABLED = 0; + + /** + * Whether shared UID migration is fully disabled. Disabled means the sharedUserMaxSdkVersion + * attribute will be directly ignored in the parsing phase. + */ + @SuppressWarnings("ConstantConditions") + public static boolean isDisabled() { + return DEFAULT == DISABLED; + } + + /** + * If the system is userdebug, returns the strategy to use by getting the system property + * {@link #PROPERTY_KEY}, or else returns the default strategy enabled in the build. + */ + public static int getCurrentStrategy() { + if (!Build.IS_USERDEBUG) { + return DEFAULT; + } + + final int s = SystemProperties.getInt(PROPERTY_KEY, DEFAULT); + // No transition strategies can be used (http://b/221088088) + if (s > BEST_EFFORT || s <= DISABLED) { + return DEFAULT; + } + return s; + } + + /** + * Should the strategy be used based on the current active strategy. + */ + public static boolean applyStrategy(@Strategy int strategy) { + return !isDisabled() && getCurrentStrategy() >= strategy; + } + + private SharedUidMigration() {} +} diff --git a/services/core/java/com/android/server/pm/SharedUserSetting.java b/services/core/java/com/android/server/pm/SharedUserSetting.java index 4d0bbc6fe437..23f0de8a5f71 100644 --- a/services/core/java/com/android/server/pm/SharedUserSetting.java +++ b/services/core/java/com/android/server/pm/SharedUserSetting.java @@ -221,6 +221,25 @@ public final class SharedUserSetting extends SettingBase implements SharedUserAp } /** + * A shared user is considered "single user" if there is exactly one single package + * currently using it. In the case when that package is also a system app, the APK on + * the system partition has to also leave shared UID. + */ + public boolean isSingleUser() { + if (mPackages.size() != 1) { + return false; + } + if (mDisabledPackages.size() > 1) { + return false; + } + if (mDisabledPackages.size() == 1) { + final AndroidPackage pkg = mDisabledPackages.valueAt(0).getPkg(); + return pkg != null && pkg.isLeavingSharedUid(); + } + return true; + } + + /** * Determine the targetSdkVersion for a sharedUser and update pkg.applicationInfo.seInfo * to ensure that all apps within the sharedUser share an SELinux domain. Use the lowest * targetSdkVersion of all apps within the shared user, which corresponds to the least diff --git a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java index ed1ab01e1d12..3eaca9dddcc4 100644 --- a/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java +++ b/services/core/java/com/android/server/pm/pkg/parsing/ParsingPackageUtils.java @@ -91,6 +91,7 @@ import com.android.internal.R; import com.android.internal.os.ClassLoaderFactory; import com.android.internal.util.ArrayUtils; import com.android.internal.util.XmlUtils; +import com.android.server.pm.SharedUidMigration; import com.android.server.pm.permission.CompatibilityPermissionInfo; import com.android.server.pm.pkg.component.ComponentMutateUtils; import com.android.server.pm.pkg.component.ComponentParseUtils; @@ -1047,8 +1048,11 @@ public class ParsingPackageUtils { } } - int maxSdkVersion = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa); - boolean leaving = (maxSdkVersion != 0) && (maxSdkVersion < Build.VERSION.RESOURCES_SDK_INT); + boolean leaving = false; + if (!SharedUidMigration.isDisabled()) { + int max = anInteger(0, R.styleable.AndroidManifest_sharedUserMaxSdkVersion, sa); + leaving = (max != 0) && (max < Build.VERSION.RESOURCES_SDK_INT); + } return input.success(pkg .setLeavingSharedUid(leaving) |