Merge "Update owner under multi-user scenarios" into udc-dev
This commit is contained in:
@@ -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}
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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] -->
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
final boolean isSameUpdateOwner =
|
||||
TextUtils.equals(oldUpdateOwner, installSource.mInstallerPackageName);
|
||||
|
||||
// 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);
|
||||
// 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 =
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user