diff options
6 files changed, 52 insertions, 22 deletions
diff --git a/core/java/android/app/admin/DelegatedAdminReceiver.java b/core/java/android/app/admin/DelegatedAdminReceiver.java index dc8dfdff2e00..0da4e7e63110 100644 --- a/core/java/android/app/admin/DelegatedAdminReceiver.java +++ b/core/java/android/app/admin/DelegatedAdminReceiver.java @@ -47,7 +47,7 @@ import android.util.Log; * * <p>The callback methods happen on the main thread of the process. Thus long running * operations must be done on another thread. Note that because a receiver - * is done once returning from its receive function, such long-running operations + * is done once returning from its onReceive function, such long-running operations * should probably be done in a {@link Service}. * * @see DevicePolicyManager#setDelegatedScopes diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java index de9297897158..8765760b216b 100644 --- a/core/java/android/app/admin/DevicePolicyManagerInternal.java +++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java @@ -118,6 +118,12 @@ public abstract class DevicePolicyManagerInternal { public abstract boolean isUserAffiliatedWithDevice(int userId); /** + * Returns whether the calling package can install or uninstall packages without user + * interaction. + */ + public abstract boolean canSilentlyInstallPackage(String callerPackage, int callerUid); + + /** * Reports that a profile has changed to use a unified or separate credential. * * @param userId User ID of the profile. diff --git a/core/java/android/content/pm/PackageInstaller.java b/core/java/android/content/pm/PackageInstaller.java index 96c30f156105..f81eb7642443 100644 --- a/core/java/android/content/pm/PackageInstaller.java +++ b/core/java/android/content/pm/PackageInstaller.java @@ -68,7 +68,14 @@ import java.util.List; * {@link PackageInstaller.Session}, which any app can create. Once the session * is created, the installer can stream one or more APKs into place until it * decides to either commit or destroy the session. Committing may require user - * intervention to complete the installation. + * intervention to complete the installation, unless the caller falls into one of the + * following categories, in which case the installation will complete automatically. + * <ul> + * <li>the device owner + * <li>the affiliated profile owner + * <li>the device owner delegated app with + * {@link android.app.admin.DevicePolicyManager#DELEGATION_PACKAGE_INSTALLATION} + * </ul> * <p> * Sessions can install brand new apps, upgrade existing apps, or add new splits * into an existing app. @@ -481,6 +488,8 @@ public class PackageInstaller { * <li>the current "installer of record" for the package * <li>the device owner * <li>the affiliated profile owner + * <li>the device owner delegated app with + * {@link android.app.admin.DevicePolicyManager#DELEGATION_PACKAGE_INSTALLATION} * </ul> * * @param packageName The package to uninstall. diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index bbec6a0055a6..a95e73069568 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -27,7 +27,6 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PackageDeleteObserver; import android.app.PackageInstallObserver; -import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManagerInternal; import android.content.Context; import android.content.Intent; @@ -738,22 +737,19 @@ public class PackageInstallerService extends IPackageInstaller.Stub implements // Check whether the caller is device owner or affiliated profile owner, in which case we do // it silently. - final int callingUserId = UserHandle.getUserId(callingUid); DevicePolicyManagerInternal dpmi = LocalServices.getService(DevicePolicyManagerInternal.class); - final boolean isDeviceOwnerOrAffiliatedProfileOwner = - dpmi != null && dpmi.isActiveAdminWithPolicy(callingUid, - DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) - && dpmi.isUserAffiliatedWithDevice(callingUserId); + final boolean canSilentlyInstallPackage = + dpmi != null && dpmi.canSilentlyInstallPackage(callerPackageName, callingUid); final PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, statusReceiver, versionedPackage.getPackageName(), - isDeviceOwnerOrAffiliatedProfileOwner, userId); + canSilentlyInstallPackage, userId); if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DELETE_PACKAGES) == PackageManager.PERMISSION_GRANTED) { // Sweet, call straight through! mPm.deletePackageVersioned(versionedPackage, adapter.getBinder(), userId, flags); - } else if (isDeviceOwnerOrAffiliatedProfileOwner) { + } else if (canSilentlyInstallPackage) { // Allow the device owner and affiliated profile owner to silently delete packages // Need to clear the calling identity to get DELETE_PACKAGES permission long ident = Binder.clearCallingIdentity(); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 26a92a4cdde4..206a88bde616 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -44,7 +44,6 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.apex.IApexService; -import android.app.admin.DeviceAdminInfo; import android.app.admin.DevicePolicyManagerInternal; import android.content.Context; import android.content.IIntentReceiver; @@ -194,7 +193,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { /** Package of the owner of the installer session */ @GuardedBy("mLock") - private String mInstallerPackageName; + private @Nullable String mInstallerPackageName; /** Uid of the owner of the installer session */ @GuardedBy("mLock") @@ -340,11 +339,12 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { */ @GuardedBy("mLock") private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked() { + if (userId != UserHandle.getUserId(mInstallerUid)) { + return false; + } DevicePolicyManagerInternal dpmi = LocalServices.getService(DevicePolicyManagerInternal.class); - return dpmi != null && dpmi.isActiveAdminWithPolicy(mInstallerUid, - DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) && dpmi.isUserAffiliatedWithDevice( - userId); + return dpmi != null && dpmi.canSilentlyInstallPackage(mInstallerPackageName, mInstallerUid); } /** diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index ab27d21dc565..7186cdf96dee 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -5385,7 +5385,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public void enforceCanManageCaCerts(ComponentName who, String callerPackage) { if (who == null) { - if (!isCallerDelegate(callerPackage, DELEGATION_CERT_INSTALL)) { + if (!isCallerDelegate(callerPackage, mInjector.binderGetCallingUid(), + DELEGATION_CERT_INSTALL)) { mContext.enforceCallingOrSelfPermission(MANAGE_CA_CERTIFICATES, null); } } else { @@ -6098,15 +6099,14 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * @param scope the delegation scope to be checked. * @return {@code true} if the calling process is a delegate of {@code scope}. */ - private boolean isCallerDelegate(String callerPackage, String scope) { + private boolean isCallerDelegate(String callerPackage, int callerUid, String scope) { Preconditions.checkNotNull(callerPackage, "callerPackage is null"); if (!Arrays.asList(DELEGATIONS).contains(scope)) { throw new IllegalArgumentException("Unexpected delegation scope: " + scope); } // Retrieve the UID and user ID of the calling process. - final int callingUid = mInjector.binderGetCallingUid(); - final int userId = UserHandle.getUserId(callingUid); + final int userId = UserHandle.getUserId(callerUid); synchronized (getLockObject()) { // Retrieve user policy data. final DevicePolicyData policy = getUserData(userId); @@ -6119,7 +6119,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final int uid = mInjector.getPackageManager() .getPackageUidAsUser(callerPackage, userId); // Return true if the caller is actually callerPackage. - return uid == callingUid; + return uid == callerUid; } catch (NameNotFoundException e) { // Ignore. } @@ -6163,7 +6163,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } else { // If no ComponentName is given ensure calling process has scope delegation or required // permission - if (isCallerDelegate(callerPackage, scope)) { + if (isCallerDelegate(callerPackage, mInjector.binderGetCallingUid(), scope)) { return; } if (permission == null) { @@ -8650,7 +8650,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { @Override public boolean isCallerApplicationRestrictionsManagingPackage(String callerPackage) { - return isCallerDelegate(callerPackage, DELEGATION_APP_RESTRICTIONS); + return isCallerDelegate(callerPackage, mInjector.binderGetCallingUid(), + DELEGATION_APP_RESTRICTIONS); } @Override @@ -10869,6 +10870,24 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } @Override + public boolean canSilentlyInstallPackage(String callerPackage, int callerUid) { + if (callerPackage == null) { + return false; + } + if (isUserAffiliatedWithDevice(UserHandle.getUserId(callerUid)) + && isActiveAdminWithPolicy(callerUid, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER)) { + // device owner or a profile owner affiliated with the device owner + return true; + } + if (DevicePolicyManagerService.this.isCallerDelegate(callerPackage, callerUid, + DELEGATION_PACKAGE_INSTALLATION)) { + return true; + } + return false; + } + + @Override public void reportSeparateProfileChallengeChanged(@UserIdInt int userId) { synchronized (getLockObject()) { updateMaximumTimeToLockLocked(userId); |