From dabae88659901d135ef807bff5dec49d86f91961 Mon Sep 17 00:00:00 2001 From: Benjamin Franz Date: Tue, 8 Aug 2017 12:33:19 +0100 Subject: [PATCH] Allow secondary user POs on affiliated devices more DPM APIs - DevicePolicyManager.setKeyguardDisabled - DevicePolicyManager.setStatusBarDisabled - DevicePolicyManager.setDeviceOwnerLockScreenInfo - PackageInstaller install and uninstall apps Bug: 64383519 Test: Can set keyguard disabled, status bar disabled and lock screen message in affliated PO Test: Can install and uninstall apps in affiliated PO Test: CTS tracked in b/68925683 Change-Id: I71be25098436ba0b42050478c049850c2b21f6f4 --- .../app/admin/DevicePolicyManagerInternal.java | 14 +++++++++++ .../android/server/pm/PackageInstallerService.java | 24 +++++++++++-------- .../android/server/pm/PackageInstallerSession.java | 27 ++++++++++++---------- .../devicepolicy/DevicePolicyManagerService.java | 26 +++++++++++++++++---- 4 files changed, 66 insertions(+), 25 deletions(-) diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java index eef2f983cc55..05f6c2a7da6d 100644 --- a/core/java/android/app/admin/DevicePolicyManagerInternal.java +++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java @@ -101,4 +101,18 @@ public abstract class DevicePolicyManagerInternal { * not enforced by the profile/device owner. */ public abstract Intent createUserRestrictionSupportIntent(int userId, String userRestriction); + + /** + * Returns whether this user/profile is affiliated with the device. + * + *

+ * By definition, the user that the device owner runs on is always affiliated with the device. + * Any other user/profile is considered affiliated with the device if the set specified by its + * profile owner via {@link DevicePolicyManager#setAffiliationIds} intersects with the device + * owner's. + *

+ * Profile owner on the primary user will never be considered as affiliated as there is no + * device owner to be affiliated with. + */ + public abstract boolean isUserAffiliatedWithDevice(int userId); } diff --git a/services/core/java/com/android/server/pm/PackageInstallerService.java b/services/core/java/com/android/server/pm/PackageInstallerService.java index be9b2f366a1f..14128a78fbac 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerService.java +++ b/services/core/java/com/android/server/pm/PackageInstallerService.java @@ -27,7 +27,8 @@ import android.app.Notification; import android.app.NotificationManager; import android.app.PackageDeleteObserver; import android.app.PackageInstallObserver; -import android.app.admin.DevicePolicyManager; +import android.app.admin.DeviceAdminInfo; +import android.app.admin.DevicePolicyManagerInternal; import android.content.Context; import android.content.Intent; import android.content.IntentSender; @@ -704,20 +705,25 @@ public class PackageInstallerService extends IPackageInstaller.Stub { mAppOps.checkPackage(callingUid, callerPackageName); } - // Check whether the caller is device owner, in which case we do it silently. - DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService( - Context.DEVICE_POLICY_SERVICE); - boolean isDeviceOwner = (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser( - callerPackageName); + // 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 PackageDeleteObserverAdapter adapter = new PackageDeleteObserverAdapter(mContext, - statusReceiver, versionedPackage.getPackageName(), isDeviceOwner, userId); + statusReceiver, versionedPackage.getPackageName(), + isDeviceOwnerOrAffiliatedProfileOwner, 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 (isDeviceOwner) { - // Allow the DeviceOwner to silently delete packages + } else if (isDeviceOwnerOrAffiliatedProfileOwner) { + // 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(); try { diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index 0e11cc7920a4..711352f905be 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -41,7 +41,8 @@ import static com.android.server.pm.PackageInstallerService.prepareStageDir; import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; -import android.app.admin.DevicePolicyManager; +import android.app.admin.DeviceAdminInfo; +import android.app.admin.DevicePolicyManagerInternal; import android.content.Context; import android.content.Intent; import android.content.IntentSender; @@ -91,6 +92,7 @@ import com.android.internal.os.SomeArgs; import com.android.internal.util.ArrayUtils; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; +import com.android.server.LocalServices; import com.android.server.pm.Installer.InstallerException; import com.android.server.pm.PackageInstallerService.PackageInstallObserverAdapter; @@ -311,14 +313,14 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { }; /** - * @return {@code true} iff the installing is app an device owner? + * @return {@code true} iff the installing is app an device owner or affiliated profile owner. */ - private boolean isInstallerDeviceOwnerLocked() { - DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService( - Context.DEVICE_POLICY_SERVICE); - - return (dpm != null) && dpm.isDeviceOwnerAppOnCallingUser( - mInstallerPackageName); + private boolean isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked() { + DevicePolicyManagerInternal dpmi = + LocalServices.getService(DevicePolicyManagerInternal.class); + return dpmi != null && dpmi.isActiveAdminWithPolicy(mInstallerUid, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) && dpmi.isUserAffiliatedWithDevice( + userId); } /** @@ -347,10 +349,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final boolean forcePermissionPrompt = (params.installFlags & PackageManager.INSTALL_FORCE_PERMISSION_PROMPT) != 0; - // Device owners are allowed to silently install packages, so the permission check is - // waived if the installer is the device owner. + // Device owners and affiliated profile owners are allowed to silently install packages, so + // the permission check is waived if the installer is the device owner. return forcePermissionPrompt || !(isPermissionGranted || isInstallerRoot - || isInstallerDeviceOwnerLocked()); + || isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked()); } public PackageInstallerSession(PackageInstallerService.InternalCallback callback, @@ -705,7 +707,8 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { assertPreparedAndNotDestroyedLocked("commit"); final PackageInstallObserverAdapter adapter = new PackageInstallObserverAdapter( - mContext, statusReceiver, sessionId, isInstallerDeviceOwnerLocked(), userId); + mContext, statusReceiver, sessionId, + isInstallerDeviceOwnerOrAffiliatedProfileOwnerLocked(), userId); mRemoteObserver = adapter.getBinder(); if (forTransfer) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 60c36d1b7203..46f893501b25 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -6943,8 +6943,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return; } + final int userId = mInjector.userHandleGetCallingUserId(); synchronized (this) { - getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + if (!isUserAffiliatedWithDeviceLocked(userId)) { + throw new SecurityException("Admin " + who + + " is neither the device owner or affiliated user's profile owner."); + } long token = mInjector.binderClearCallingIdentity(); try { mLockPatternUtils.setDeviceOwnerInfo(info != null ? info.toString() : null); @@ -9236,10 +9241,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean setKeyguardDisabled(ComponentName who, boolean disabled) { Preconditions.checkNotNull(who, "ComponentName is null"); + final int userId = mInjector.userHandleGetCallingUserId(); synchronized (this) { - getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + if (!isUserAffiliatedWithDeviceLocked(userId)) { + throw new SecurityException("Admin " + who + + " is neither the device owner or affiliated user's profile owner."); + } } - final int userId = UserHandle.getCallingUserId(); long ident = mInjector.binderClearCallingIdentity(); try { @@ -9261,7 +9270,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { public boolean setStatusBarDisabled(ComponentName who, boolean disabled) { int userId = UserHandle.getCallingUserId(); synchronized (this) { - getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + if (!isUserAffiliatedWithDeviceLocked(userId)) { + throw new SecurityException("Admin " + who + + " is neither the device owner or affiliated user's profile owner."); + } DevicePolicyData policy = getUserData(userId); if (policy.mStatusBarDisabled != disabled) { boolean isLockTaskMode = false; @@ -9526,6 +9539,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } return null; } + + @Override + public boolean isUserAffiliatedWithDevice(int userId) { + return DevicePolicyManagerService.this.isUserAffiliatedWithDeviceLocked(userId); + } } private Intent createShowAdminSupportIntent(ComponentName admin, int userId) { -- 2.11.0