diff options
author | 2023-02-20 01:07:59 +0000 | |
---|---|---|
committer | 2023-02-20 01:07:59 +0000 | |
commit | e835a95134ffaeb2e2bd4b018b2d2f8fc7908825 (patch) | |
tree | 2dc6252ae6bd0df65d0fa47b0ced32779ed2205b | |
parent | 33fa85221bf736c192a8bdf001be7ae134463162 (diff) | |
parent | 4020ef00a16360419b0a2a3eca3dc8fc84e3a2b7 (diff) |
Merge "Update owner under multi-user scenarios" into udc-dev
8 files changed, 117 insertions, 59 deletions
diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 2b4ea70aabf4..7766896c7367 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -581,7 +581,7 @@ public class PackageInstaller { /** * Indicate the user intervention is required because the update ownership enforcement is - * enabled, and remind the update owner will retain. + * enabled, and remind the update owner is a different package. * * @see PackageInstaller.SessionParams#setRequestUpdateOwnership * @see InstallSourceInfo#getUpdateOwnerPackageName @@ -2978,8 +2978,7 @@ public class PackageInstaller { * permission. Default to {@code false}. * * The update ownership enforcement can only be enabled on initial installation. Set - * this to {@code true} on package update indicates the installer package wants to be - * the update owner if the update ownership enforcement has enabled. + * this to {@code true} on package update is a no-op. * * Note: To enable the update ownership enforcement, the installer must have the * {@link android.Manifest.permission#ENFORCE_UPDATE_OWNERSHIP ENFORCE_UPDATE_OWNERSHIP} diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 23cce6a1c135..db05b959a7b1 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -1607,6 +1607,13 @@ public abstract class PackageManager { */ public static final int INSTALL_REQUEST_UPDATE_OWNERSHIP = 1 << 25; + /** + * Flag parameter for {@link PackageInstaller.SessionParams} to indicate that this + * session is from a managed user or profile. + * @hide + */ + public static final int INSTALL_FROM_MANAGED_USER_OR_PROFILE = 1 << 26; + /** @hide */ @IntDef(flag = true, value = { DONT_KILL_APP, diff --git a/packages/PackageInstaller/res/values/strings.xml b/packages/PackageInstaller/res/values/strings.xml index ab680b063d6d..6669e358eb08 100644 --- a/packages/PackageInstaller/res/values/strings.xml +++ b/packages/PackageInstaller/res/values/strings.xml @@ -38,9 +38,6 @@ <!-- Message for updating an existing app [CHAR LIMIT=NONE] --> <string name="install_confirm_question_update">Do you want to update this app?</string> <!-- TODO(b/244413073) Revise the description after getting UX input and UXR on this. --> - <!-- Message for updating an existing app when updating owner changed [DO NOT TRANSLATE][CHAR LIMIT=NONE] --> - <string name="install_confirm_question_update_owner_changed">Updates to this app are currently managed by <xliff:g id="existing_update_owner">%1$s</xliff:g>.\n\nBy updating, you\'ll get future updates from <xliff:g id="new_update_owner">%2$s</xliff:g> instead.</string> - <!-- TODO(b/244413073) Revise the description after getting UX input and UXR on this. --> <!-- Message for updating an existing app with update owner reminder [DO NOT TRANSLATE][CHAR LIMIT=NONE] --> <string name="install_confirm_question_update_owner_reminder">Updates to this app are currently managed by <xliff:g id="existing_update_owner">%1$s</xliff:g>.\n\nDo you want to install this update from <xliff:g id="new_update_owner">%2$s</xliff:g>?</string> <!-- [CHAR LIMIT=100] --> diff --git a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java index fd41f5fb08a5..d41cfbc2d4ce 100644 --- a/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java +++ b/packages/PackageInstaller/src/com/android/packageinstaller/PackageInstallerActivity.java @@ -144,18 +144,11 @@ public class PackageInstallerActivity extends AlertActivity { final CharSequence existingUpdateOwnerLabel = getExistingUpdateOwnerLabel(); final CharSequence requestedUpdateOwnerLabel = getApplicationLabel(mCallingPackage); - if (!TextUtils.isEmpty(existingUpdateOwnerLabel)) { - if (mPendingUserActionReason == PackageInstaller.REASON_OWNERSHIP_CHANGED) { - viewToEnable.setText( - getString(R.string.install_confirm_question_update_owner_changed, - existingUpdateOwnerLabel, requestedUpdateOwnerLabel)); - } else if (mPendingUserActionReason == PackageInstaller.REASON_REMIND_OWNERSHIP - || mPendingUserActionReason - == PackageInstaller.REASON_CONFIRM_PACKAGE_CHANGE) { - viewToEnable.setText( - getString(R.string.install_confirm_question_update_owner_reminder, - existingUpdateOwnerLabel, requestedUpdateOwnerLabel)); - } + if (!TextUtils.isEmpty(existingUpdateOwnerLabel) + && mPendingUserActionReason == PackageInstaller.REASON_REMIND_OWNERSHIP) { + viewToEnable.setText( + getString(R.string.install_confirm_question_update_owner_reminder, + existingUpdateOwnerLabel, requestedUpdateOwnerLabel)); } mOk.setText(R.string.update); diff --git a/services/core/java/com/android/server/pm/ComputerEngine.java b/services/core/java/com/android/server/pm/ComputerEngine.java index 58a609e3e370..5984360a534c 100644 --- a/services/core/java/com/android/server/pm/ComputerEngine.java +++ b/services/core/java/com/android/server/pm/ComputerEngine.java @@ -65,6 +65,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.UserIdInt; import android.app.ActivityManager; +import android.app.admin.DevicePolicyManagerInternal; import android.content.ComponentName; import android.content.Context; import android.content.Intent; @@ -2190,6 +2191,11 @@ public class ComputerEngine implements Computer { && UserHandle.getAppId(uid) == pkg.getUid(); } + private boolean isCallerFromManagedUserOrProfile(@UserIdInt int userId) { + final var dpmi = mInjector.getLocalService(DevicePolicyManagerInternal.class); + return dpmi != null && dpmi.isUserOrganizationManaged(userId); + } + public final boolean isComponentVisibleToInstantApp(@Nullable ComponentName component) { if (isComponentVisibleToInstantApp(component, TYPE_ACTIVITY)) { return true; @@ -5002,8 +5008,15 @@ public class ComputerEngine implements Computer { updateOwnerPackageName = installSource.mUpdateOwnerPackageName; if (updateOwnerPackageName != null) { final PackageStateInternal ps = mSettings.getPackage(updateOwnerPackageName); + final boolean isCallerSystemOrUpdateOwner = callingUid == Process.SYSTEM_UID + || isCallerSameApp(updateOwnerPackageName, callingUid); + // Except for package visibility filtering, we also hide update owner if the installer + // is in the managed user or profile. As we don't enforce the update ownership for the + // managed user and profile, knowing there's an update owner is meaningless in that + // user unless the installer is the owner. if (ps == null - || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId)) { + || shouldFilterApplicationIncludingUninstalled(ps, callingUid, userId) + || (!isCallerSystemOrUpdateOwner && isCallerFromManagedUserOrProfile(userId))) { updateOwnerPackageName = null; } } diff --git a/services/core/java/com/android/server/pm/InstallPackageHelper.java b/services/core/java/com/android/server/pm/InstallPackageHelper.java index 4b2be2ff500d..a868470b0042 100644 --- a/services/core/java/com/android/server/pm/InstallPackageHelper.java +++ b/services/core/java/com/android/server/pm/InstallPackageHelper.java @@ -102,6 +102,7 @@ import android.app.AppOpsManager; import android.app.ApplicationExitInfo; import android.app.ApplicationPackageManager; import android.app.BroadcastOptions; +import android.app.admin.DevicePolicyManagerInternal; import android.app.backup.IBackupManager; import android.content.ContentResolver; import android.content.Context; @@ -144,6 +145,7 @@ import android.provider.DeviceConfig; import android.stats.storage.StorageEnums; import android.system.ErrnoException; import android.system.Os; +import android.text.TextUtils; import android.util.ArrayMap; import android.util.ArraySet; import android.util.EventLog; @@ -317,10 +319,16 @@ final class InstallPackageHelper { InstallSource installSource = request.getInstallSource(); final boolean isApex = (scanFlags & SCAN_AS_APEX) != 0; + final boolean pkgAlreadyExists = oldPkgSetting != null; + final boolean isAllowUpdateOwnership = parsedPackage.isAllowUpdateOwnership(); + final String oldUpdateOwner = + pkgAlreadyExists ? oldPkgSetting.getInstallSource().mUpdateOwnerPackageName : null; final String updateOwnerFromSysconfig = isApex || !pkgSetting.isSystem() ? null : mPm.mInjector.getSystemConfig().getSystemAppUpdateOwnerPackageName( parsedPackage.getPackageName()); - // For new install (standard install), the installSource isn't null. + final boolean isUpdateOwnershipEnabled = oldUpdateOwner != null; + + // For standard install (install via session), the installSource isn't null. if (installSource != null) { // If this is part of a standard install, set the initiating package name, else rely on // previous device state. @@ -334,39 +342,68 @@ final class InstallPackageHelper { } // Handle the update ownership enforcement for APK - if (updateOwnerFromSysconfig != null) { - // For system app, we always use the update owner from sysconfig if presented. - installSource = installSource.setUpdateOwnerPackageName(updateOwnerFromSysconfig); - } else if (!parsedPackage.isAllowUpdateOwnership()) { + if (!isAllowUpdateOwnership) { // If the app wants to opt-out of the update ownership enforcement via manifest, // it overrides the installer's use of #setRequestUpdateOwnership. installSource = installSource.setUpdateOwnerPackageName(null); } else if (!isApex) { - final boolean isUpdate = oldPkgSetting != null; - final String oldUpdateOwner = - isUpdate ? oldPkgSetting.getInstallSource().mUpdateOwnerPackageName : null; - final boolean isUpdateOwnershipEnabled = oldUpdateOwner != null; + // User installer UID as "current" userId if present; otherwise, use the userId + // from InstallRequest. + final int userId = installSource.mInstallerPackageUid != Process.INVALID_UID + ? UserHandle.getUserId(installSource.mInstallerPackageUid) + : request.getUserId(); + // Whether the parsedPackage is installed on the userId + // If the oldPkgSetting doesn't exist, this package isn't installed for all users. + final boolean isUpdate = pkgAlreadyExists && (userId >= UserHandle.USER_SYSTEM + // If userID >= 0, we could check via oldPkgSetting.getInstalled(userId). + ? oldPkgSetting.getInstalled(userId) + // When userId is -1 (USER_ALL) and it's not installed for any user, + // treat it as not installed. + : oldPkgSetting.getNotInstalledUserIds().length + <= (UserManager.isHeadlessSystemUserMode() ? 1 : 0)); final boolean isRequestUpdateOwnership = (request.getInstallFlags() & PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP) != 0; - - // Here we assign the update owner for the package, and the rules are: - // -. If the installer doesn't request update ownership on initial installation, - // keep the update owner as null. - // -. If the installer doesn't want to be the owner to provide the subsequent - // update (doesn't request to be the update owner), e.g., non-store installer - // (file manager), ADB, or DO/PO, we should not update the owner. - // -. Else, the installer requests update ownership on initial installation or - // update, we use installSource.mUpdateOwnerPackageName as the update owner. - if (!isRequestUpdateOwnership || (isUpdate && !isUpdateOwnershipEnabled)) { - installSource = installSource.setUpdateOwnerPackageName(oldUpdateOwner); + final boolean isSameUpdateOwner = + TextUtils.equals(oldUpdateOwner, installSource.mInstallerPackageName); + + // Here we handle the update owner for the package, and the rules are: + // -. Only enabling update ownership enforcement on initial installation if the + // installer has requested. + // -. Once the installer changes and users agree to proceed, clear the update + // owner (package state in other users are taken into account as well). + if (!isUpdate) { + if (!isRequestUpdateOwnership) { + installSource = installSource.setUpdateOwnerPackageName(null); + } else if ((!isUpdateOwnershipEnabled && pkgAlreadyExists) + || (isUpdateOwnershipEnabled && !isSameUpdateOwner)) { + installSource = installSource.setUpdateOwnerPackageName(null); + } + } else if (!isSameUpdateOwner || !isUpdateOwnershipEnabled) { + installSource = installSource.setUpdateOwnerPackageName(null); } } pkgSetting.setInstallSource(installSource); - // non-standard install (addForInit and install existing packages), installSource is null. - } else if (updateOwnerFromSysconfig != null) { - // For system app, we always use the update owner from sysconfig if presented. - pkgSetting.setUpdateOwnerPackage(updateOwnerFromSysconfig); + // For non-standard install (addForInit), installSource is null. + } else if (pkgSetting.isSystem()) { + // We still honor the manifest attr if the system app wants to opt-out of it. + if (!isAllowUpdateOwnership) { + pkgSetting.setUpdateOwnerPackage(null); + } else { + final boolean isSameUpdateOwner = isUpdateOwnershipEnabled + && TextUtils.equals(oldUpdateOwner, updateOwnerFromSysconfig); + + // Here we handle the update owner for the system package, and the rules are: + // -. We use the update owner from sysconfig as the initial value. + // -. Once an app becomes to system app later via OTA, only retains the update + // owner if it's consistence with sysconfig. + // -. Clear the update owner when update owner changes from sysconfig. + if (!pkgAlreadyExists || isSameUpdateOwner) { + pkgSetting.setUpdateOwnerPackage(updateOwnerFromSysconfig); + } else { + pkgSetting.setUpdateOwnerPackage(null); + } + } } if ((scanFlags & SCAN_AS_APK_IN_APEX) != 0) { @@ -641,6 +678,18 @@ final class InstallPackageHelper { } if (installed) { + final String updateOwner = pkgSetting.getInstallSource().mUpdateOwnerPackageName; + final var dpmi = mInjector.getLocalService(DevicePolicyManagerInternal.class); + final boolean isFromManagedUserOrProfile = + dpmi != null && dpmi.isUserOrganizationManaged(userId); + // Here we handle the update owner when install existing package, and the rules are: + // -. Retain the update owner when enable a system app in managed user or profile. + // -. Retain the update owner if the installer is the same. + // -. Clear the update owner when update owner changes. + if (!preLockSnapshot.isCallerSameApp(updateOwner, callingUid) + && (!pkgSetting.isSystem() || !isFromManagedUserOrProfile)) { + pkgSetting.setUpdateOwnerPackage(null); + } if (pkgSetting.getPkg() != null) { final PermissionManagerServiceInternal.PackageInstalledParams.Builder permissionParamsBuilder = diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index 77ffa165b6ad..adc0b0b6fc6a 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -926,6 +926,11 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements requestedInstallerPackageName = null; } + final var dpmi = LocalServices.getService(DevicePolicyManagerInternal.class); + if (dpmi != null && dpmi.isUserOrganizationManaged(userId)) { + params.installFlags |= PackageManager.INSTALL_FROM_MANAGED_USER_OR_PROFILE; + } + if (isApex || mContext.checkCallingOrSelfPermission( Manifest.permission.ENFORCE_UPDATE_OWNERSHIP) == PackageManager.PERMISSION_DENIED) { params.installFlags &= ~PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP; diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index fb6ae8b50a26..fa535c38c5d2 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -868,15 +868,13 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final int USER_ACTION_NOT_NEEDED = 0; private static final int USER_ACTION_REQUIRED = 1; private static final int USER_ACTION_PENDING_APK_PARSING = 2; - private static final int USER_ACTION_REQUIRED_UPDATE_OWNER_CHANGED = 3; - private static final int USER_ACTION_REQUIRED_UPDATE_OWNER_RETAINED = 4; + private static final int USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER = 3; @IntDef({ USER_ACTION_NOT_NEEDED, USER_ACTION_REQUIRED, USER_ACTION_PENDING_APK_PARSING, - USER_ACTION_REQUIRED_UPDATE_OWNER_CHANGED, - USER_ACTION_REQUIRED_UPDATE_OWNER_RETAINED + USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER, }) @interface UserActionRequirement {} @@ -937,7 +935,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { : null; final boolean isInstallerOfRecord = isUpdate && Objects.equals(existingInstallerPackageName, getInstallerPackageName()); - final boolean isUpdateOwner = Objects.equals(existingUpdateOwnerPackageName, + final boolean isUpdateOwner = TextUtils.equals(existingUpdateOwnerPackageName, getInstallerPackageName()); final boolean isSelfUpdate = targetPackageUid == mInstallerUid; final boolean isPermissionGranted = isInstallPermissionGranted @@ -947,6 +945,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final boolean isInstallerRoot = (mInstallerUid == Process.ROOT_UID); final boolean isInstallerSystem = (mInstallerUid == Process.SYSTEM_UID); final boolean isInstallerShell = (mInstallerUid == Process.SHELL_UID); + final boolean isFromManagedUserOrProfile = + (params.installFlags & PackageManager.INSTALL_FROM_MANAGED_USER_OR_PROFILE) != 0; final boolean isUpdateOwnershipEnforcementEnabled = mPm.isUpdateOwnershipEnforcementAvailable() && existingUpdateOwnerPackageName != null; @@ -963,12 +963,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (isUpdateOwnershipEnforcementEnabled && !isApexSession() && !isUpdateOwner - && !isInstallerShell) { - final boolean isRequestUpdateOwner = - (params.installFlags & PackageManager.INSTALL_REQUEST_UPDATE_OWNERSHIP) != 0; - - return isRequestUpdateOwner ? USER_ACTION_REQUIRED_UPDATE_OWNER_CHANGED - : USER_ACTION_REQUIRED_UPDATE_OWNER_RETAINED; + && !isInstallerShell + // We don't enforce the update ownership for the managed user and profile. + && !isFromManagedUserOrProfile) { + return USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER; } if (isPermissionGranted) { @@ -2361,8 +2359,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { userActionRequirement = session.computeUserActionRequirement(); session.updateUserActionRequirement(userActionRequirement); if (userActionRequirement == USER_ACTION_REQUIRED - || userActionRequirement == USER_ACTION_REQUIRED_UPDATE_OWNER_CHANGED - || userActionRequirement == USER_ACTION_REQUIRED_UPDATE_OWNER_RETAINED) { + || userActionRequirement == USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER) { session.sendPendingUserActionIntent(target); return true; } @@ -2425,9 +2422,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static @UserActionReason int userActionRequirementToReason( @UserActionRequirement int requirement) { switch (requirement) { - case USER_ACTION_REQUIRED_UPDATE_OWNER_CHANGED: - return PackageInstaller.REASON_OWNERSHIP_CHANGED; - case USER_ACTION_REQUIRED_UPDATE_OWNER_RETAINED: + case USER_ACTION_REQUIRED_UPDATE_OWNER_REMINDER: return PackageInstaller.REASON_REMIND_OWNERSHIP; default: return PackageInstaller.REASON_CONFIRM_PACKAGE_CHANGE; |