Loading core/java/android/app/admin/DevicePolicyManager.java +40 −0 Original line number Diff line number Diff line Loading @@ -8753,4 +8753,44 @@ public class DevicePolicyManager { throw re.rethrowFromSystemServer(); } } //TODO STOPSHIP Add link to onTransferComplete callback when implemented. /** * Transfers the current administrator. All policies from the current administrator are * migrated to the new administrator. The whole operation is atomic - the transfer is either * complete or not done at all. * * Depending on the current administrator (device owner, profile owner, corporate owned * profile owner), you have the following expected behaviour: * <ul> * <li>A device owner can only be transferred to a new device owner</li> * <li>A profile owner can only be transferred to a new profile owner</li> * <li>A corporate owned managed profile can have two cases: * <ul> * <li>If the device owner and profile owner are the same package, * both will be transferred.</li> * <li>If the device owner and profile owner are different packages, * and if this method is called from the profile owner, only the profile owner * is transferred. Similarly, if it is called from the device owner, only * the device owner is transferred.</li> * </ul> * </li> * </ul> * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param target Which {@link DeviceAdminReceiver} we want the new administrator to be. * @param bundle Parameters - This bundle allows the current administrator to pass data to the * new administrator. The parameters will be received in the * onTransferComplete callback. * @hide */ public void transferOwner(@NonNull ComponentName admin, @NonNull ComponentName target, PersistableBundle bundle) { throwIfParentInstance("transferOwner"); try { mService.transferOwner(admin, target, bundle); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } } } core/java/android/app/admin/IDevicePolicyManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -378,4 +378,5 @@ interface IDevicePolicyManager { boolean isLogoutEnabled(); List<String> getDisallowedSystemApps(in ComponentName admin, int userId, String provisioningAction); void transferOwner(in ComponentName admin, in ComponentName target, in PersistableBundle bundle); } services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java +3 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.devicepolicy; import android.app.admin.IDevicePolicyManager; import android.content.ComponentName; import android.os.PersistableBundle; import com.android.internal.R; import com.android.server.SystemService; Loading Loading @@ -57,4 +58,6 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { abstract void handleStopUser(int userId); public void setSystemSetting(ComponentName who, String setting, String value){} public void transferOwner(ComponentName admin, ComponentName target, PersistableBundle bundle) {} } services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +109 −20 Original line number Diff line number Diff line Loading @@ -751,7 +751,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications"; private static final String TAG_IS_LOGOUT_ENABLED = "is_logout_enabled"; final DeviceAdminInfo info; DeviceAdminInfo info; static final int DEF_PASSWORD_HISTORY_LENGTH = 0; Loading Loading @@ -1402,6 +1402,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return userRestrictions; } public void transfer(DeviceAdminInfo deviceAdminInfo) { if (hasParentActiveAdmin()) { parentAdmin.info = deviceAdminInfo; } info = deviceAdminInfo; } void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("uid="); pw.println(getUid()); pw.print(prefix); pw.print("testOnlyAdmin="); Loading Loading @@ -2541,7 +2548,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle, boolean throwForMissiongPermission) { boolean throwForMissingPermission) { if (!mHasFeature) { return null; } Loading @@ -2564,7 +2571,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final String message = "DeviceAdminReceiver " + adminName + " must be protected with " + permission.BIND_DEVICE_ADMIN; Slog.w(LOG_TAG, message); if (throwForMissiongPermission && if (throwForMissingPermission && ai.applicationInfo.targetSdkVersion > Build.VERSION_CODES.M) { throw new IllegalArgumentException(message); } Loading Loading @@ -2889,7 +2896,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { try { DeviceAdminInfo dai = findAdmin( ComponentName.unflattenFromString(name), userHandle, /* throwForMissionPermission= */ false); /* throwForMissingPermission= */ false); if (VERBOSE_LOG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid) != userHandle)) { Loading Loading @@ -3293,19 +3300,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { DevicePolicyData policy = getUserData(userHandle); DeviceAdminInfo info = findAdmin(adminReceiver, userHandle, /* throwForMissionPermission= */ true); if (info == null) { throw new IllegalArgumentException("Bad admin: " + adminReceiver); } if (!info.getActivityInfo().applicationInfo.isInternal()) { throw new IllegalArgumentException("Only apps in internal storage can be active admin: " + adminReceiver); } if (info.getActivityInfo().applicationInfo.isInstantApp()) { throw new IllegalArgumentException("Instant apps cannot be device admins: " + adminReceiver); } /* throwForMissingPermission= */ true); synchronized (this) { checkActiveAdminPrecondition(adminReceiver, info, policy); long ident = mInjector.binderClearCallingIdentity(); try { final ActiveAdmin existingAdmin Loading @@ -3313,10 +3310,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (!refreshing && existingAdmin != null) { throw new IllegalArgumentException("Admin is already added"); } if (policy.mRemovingAdmins.contains(adminReceiver)) { throw new IllegalArgumentException( "Trying to set an admin which is being removed"); } ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false); newAdmin.testOnlyAdmin = (existingAdmin != null) ? existingAdmin.testOnlyAdmin Loading Loading @@ -3346,6 +3339,46 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } private void transferActiveAdminUncheckedLocked(ComponentName incomingReceiver, ComponentName outgoingReceiver, int userHandle) { final DevicePolicyData policy = getUserData(userHandle); final DeviceAdminInfo incomingDeviceInfo = findAdmin(incomingReceiver, userHandle, /* throwForMissingPermission= */ true); final ActiveAdmin adminToTransfer = policy.mAdminMap.get(outgoingReceiver); final int oldAdminUid = adminToTransfer.getUid(); adminToTransfer.transfer(incomingDeviceInfo); policy.mAdminMap.remove(outgoingReceiver); policy.mAdminMap.put(incomingReceiver, adminToTransfer); if (policy.mPasswordOwner == oldAdminUid) { policy.mPasswordOwner = adminToTransfer.getUid(); } saveSettingsLocked(userHandle); //TODO: Make sure we revert back when we detect a failure. sendAdminCommandLocked(adminToTransfer, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED, null, null); } private void checkActiveAdminPrecondition(ComponentName adminReceiver, DeviceAdminInfo info, DevicePolicyData policy) { if (info == null) { throw new IllegalArgumentException("Bad admin: " + adminReceiver); } if (!info.getActivityInfo().applicationInfo.isInternal()) { throw new IllegalArgumentException("Only apps in internal storage can be active admin: " + adminReceiver); } if (info.getActivityInfo().applicationInfo.isInstantApp()) { throw new IllegalArgumentException("Instant apps cannot be device admins: " + adminReceiver); } if (policy.mRemovingAdmins.contains(adminReceiver)) { throw new IllegalArgumentException( "Trying to set an admin which is being removed"); } } @Override public boolean isAdminActive(ComponentName adminReceiver, int userHandle) { if (!mHasFeature) { Loading Loading @@ -11538,4 +11571,60 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return new ArrayList<>( mOverlayPackagesProvider.getNonRequiredApps(admin, userId, provisioningAction)); } //TODO: Add callback information to the javadoc once it is completed. //TODO: Make transferOwner atomic. @Override public void transferOwner(ComponentName admin, ComponentName target, PersistableBundle bundle) { if (!mHasFeature) { return; } Preconditions.checkNotNull(admin, "Admin cannot be null."); Preconditions.checkNotNull(target, "Target cannot be null."); enforceProfileOrDeviceOwner(admin); if (admin.equals(target)) { throw new IllegalArgumentException("Provided administrator and target are " + "the same object."); } if (admin.getPackageName().equals(target.getPackageName())) { throw new IllegalArgumentException("Provided administrator and target have " + "the same package name."); } final int callingUserId = mInjector.userHandleGetCallingUserId(); final DevicePolicyData policy = getUserData(callingUserId); final DeviceAdminInfo incomingDeviceInfo = findAdmin(target, callingUserId, /* throwForMissingPermission= */ true); checkActiveAdminPrecondition(target, incomingDeviceInfo, policy); final long id = mInjector.binderClearCallingIdentity(); try { //STOPSHIP add support for COMP, DO, edge cases when device is rebooted/work mode off, //transfer callbacks and broadcast if (isProfileOwner(admin, callingUserId)) { transferProfileOwner(admin, target, callingUserId); } } finally { mInjector.binderRestoreCallingIdentity(id); } } /** * Transfers the profile owner for user with id profileOwnerUserId from admin to target. */ private void transferProfileOwner(ComponentName admin, ComponentName target, int profileOwnerUserId) { synchronized (this) { transferActiveAdminUncheckedLocked(target, admin, profileOwnerUserId); mOwners.transferProfileOwner(target, profileOwnerUserId); Slog.i(LOG_TAG, "Profile owner set: " + target + " on user " + profileOwnerUserId); mOwners.writeProfileOwner(profileOwnerUserId); mDeviceAdminServiceController.startServiceForOwner( target.getPackageName(), profileOwnerUserId, "transfer-profile-owner"); } } } services/devicepolicy/java/com/android/server/devicepolicy/Owners.java +11 −0 Original line number Diff line number Diff line Loading @@ -277,6 +277,17 @@ class Owners { } } void transferProfileOwner(ComponentName target, int userId) { synchronized (mLock) { final OwnerInfo ownerInfo = mProfileOwners.get(userId); final OwnerInfo newOwnerInfo = new OwnerInfo(target.getPackageName(), target, ownerInfo.userRestrictionsMigrated, ownerInfo.remoteBugreportUri, ownerInfo.remoteBugreportHash); mProfileOwners.put(userId, newOwnerInfo); pushToPackageManagerLocked(); } } ComponentName getProfileOwnerComponent(int userId) { synchronized (mLock) { OwnerInfo profileOwner = mProfileOwners.get(userId); Loading Loading
core/java/android/app/admin/DevicePolicyManager.java +40 −0 Original line number Diff line number Diff line Loading @@ -8753,4 +8753,44 @@ public class DevicePolicyManager { throw re.rethrowFromSystemServer(); } } //TODO STOPSHIP Add link to onTransferComplete callback when implemented. /** * Transfers the current administrator. All policies from the current administrator are * migrated to the new administrator. The whole operation is atomic - the transfer is either * complete or not done at all. * * Depending on the current administrator (device owner, profile owner, corporate owned * profile owner), you have the following expected behaviour: * <ul> * <li>A device owner can only be transferred to a new device owner</li> * <li>A profile owner can only be transferred to a new profile owner</li> * <li>A corporate owned managed profile can have two cases: * <ul> * <li>If the device owner and profile owner are the same package, * both will be transferred.</li> * <li>If the device owner and profile owner are different packages, * and if this method is called from the profile owner, only the profile owner * is transferred. Similarly, if it is called from the device owner, only * the device owner is transferred.</li> * </ul> * </li> * </ul> * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param target Which {@link DeviceAdminReceiver} we want the new administrator to be. * @param bundle Parameters - This bundle allows the current administrator to pass data to the * new administrator. The parameters will be received in the * onTransferComplete callback. * @hide */ public void transferOwner(@NonNull ComponentName admin, @NonNull ComponentName target, PersistableBundle bundle) { throwIfParentInstance("transferOwner"); try { mService.transferOwner(admin, target, bundle); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } } }
core/java/android/app/admin/IDevicePolicyManager.aidl +1 −0 Original line number Diff line number Diff line Loading @@ -378,4 +378,5 @@ interface IDevicePolicyManager { boolean isLogoutEnabled(); List<String> getDisallowedSystemApps(in ComponentName admin, int userId, String provisioningAction); void transferOwner(in ComponentName admin, in ComponentName target, in PersistableBundle bundle); }
services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java +3 −0 Original line number Diff line number Diff line Loading @@ -17,6 +17,7 @@ package com.android.server.devicepolicy; import android.app.admin.IDevicePolicyManager; import android.content.ComponentName; import android.os.PersistableBundle; import com.android.internal.R; import com.android.server.SystemService; Loading Loading @@ -57,4 +58,6 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { abstract void handleStopUser(int userId); public void setSystemSetting(ComponentName who, String setting, String value){} public void transferOwner(ComponentName admin, ComponentName target, PersistableBundle bundle) {} }
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +109 −20 Original line number Diff line number Diff line Loading @@ -751,7 +751,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { private static final String ATTR_NUM_NETWORK_LOGGING_NOTIFICATIONS = "num-notifications"; private static final String TAG_IS_LOGOUT_ENABLED = "is_logout_enabled"; final DeviceAdminInfo info; DeviceAdminInfo info; static final int DEF_PASSWORD_HISTORY_LENGTH = 0; Loading Loading @@ -1402,6 +1402,13 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return userRestrictions; } public void transfer(DeviceAdminInfo deviceAdminInfo) { if (hasParentActiveAdmin()) { parentAdmin.info = deviceAdminInfo; } info = deviceAdminInfo; } void dump(String prefix, PrintWriter pw) { pw.print(prefix); pw.print("uid="); pw.println(getUid()); pw.print(prefix); pw.print("testOnlyAdmin="); Loading Loading @@ -2541,7 +2548,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle, boolean throwForMissiongPermission) { boolean throwForMissingPermission) { if (!mHasFeature) { return null; } Loading @@ -2564,7 +2571,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final String message = "DeviceAdminReceiver " + adminName + " must be protected with " + permission.BIND_DEVICE_ADMIN; Slog.w(LOG_TAG, message); if (throwForMissiongPermission && if (throwForMissingPermission && ai.applicationInfo.targetSdkVersion > Build.VERSION_CODES.M) { throw new IllegalArgumentException(message); } Loading Loading @@ -2889,7 +2896,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { try { DeviceAdminInfo dai = findAdmin( ComponentName.unflattenFromString(name), userHandle, /* throwForMissionPermission= */ false); /* throwForMissingPermission= */ false); if (VERBOSE_LOG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid) != userHandle)) { Loading Loading @@ -3293,19 +3300,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { DevicePolicyData policy = getUserData(userHandle); DeviceAdminInfo info = findAdmin(adminReceiver, userHandle, /* throwForMissionPermission= */ true); if (info == null) { throw new IllegalArgumentException("Bad admin: " + adminReceiver); } if (!info.getActivityInfo().applicationInfo.isInternal()) { throw new IllegalArgumentException("Only apps in internal storage can be active admin: " + adminReceiver); } if (info.getActivityInfo().applicationInfo.isInstantApp()) { throw new IllegalArgumentException("Instant apps cannot be device admins: " + adminReceiver); } /* throwForMissingPermission= */ true); synchronized (this) { checkActiveAdminPrecondition(adminReceiver, info, policy); long ident = mInjector.binderClearCallingIdentity(); try { final ActiveAdmin existingAdmin Loading @@ -3313,10 +3310,6 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { if (!refreshing && existingAdmin != null) { throw new IllegalArgumentException("Admin is already added"); } if (policy.mRemovingAdmins.contains(adminReceiver)) { throw new IllegalArgumentException( "Trying to set an admin which is being removed"); } ActiveAdmin newAdmin = new ActiveAdmin(info, /* parent */ false); newAdmin.testOnlyAdmin = (existingAdmin != null) ? existingAdmin.testOnlyAdmin Loading Loading @@ -3346,6 +3339,46 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } private void transferActiveAdminUncheckedLocked(ComponentName incomingReceiver, ComponentName outgoingReceiver, int userHandle) { final DevicePolicyData policy = getUserData(userHandle); final DeviceAdminInfo incomingDeviceInfo = findAdmin(incomingReceiver, userHandle, /* throwForMissingPermission= */ true); final ActiveAdmin adminToTransfer = policy.mAdminMap.get(outgoingReceiver); final int oldAdminUid = adminToTransfer.getUid(); adminToTransfer.transfer(incomingDeviceInfo); policy.mAdminMap.remove(outgoingReceiver); policy.mAdminMap.put(incomingReceiver, adminToTransfer); if (policy.mPasswordOwner == oldAdminUid) { policy.mPasswordOwner = adminToTransfer.getUid(); } saveSettingsLocked(userHandle); //TODO: Make sure we revert back when we detect a failure. sendAdminCommandLocked(adminToTransfer, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED, null, null); } private void checkActiveAdminPrecondition(ComponentName adminReceiver, DeviceAdminInfo info, DevicePolicyData policy) { if (info == null) { throw new IllegalArgumentException("Bad admin: " + adminReceiver); } if (!info.getActivityInfo().applicationInfo.isInternal()) { throw new IllegalArgumentException("Only apps in internal storage can be active admin: " + adminReceiver); } if (info.getActivityInfo().applicationInfo.isInstantApp()) { throw new IllegalArgumentException("Instant apps cannot be device admins: " + adminReceiver); } if (policy.mRemovingAdmins.contains(adminReceiver)) { throw new IllegalArgumentException( "Trying to set an admin which is being removed"); } } @Override public boolean isAdminActive(ComponentName adminReceiver, int userHandle) { if (!mHasFeature) { Loading Loading @@ -11538,4 +11571,60 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { return new ArrayList<>( mOverlayPackagesProvider.getNonRequiredApps(admin, userId, provisioningAction)); } //TODO: Add callback information to the javadoc once it is completed. //TODO: Make transferOwner atomic. @Override public void transferOwner(ComponentName admin, ComponentName target, PersistableBundle bundle) { if (!mHasFeature) { return; } Preconditions.checkNotNull(admin, "Admin cannot be null."); Preconditions.checkNotNull(target, "Target cannot be null."); enforceProfileOrDeviceOwner(admin); if (admin.equals(target)) { throw new IllegalArgumentException("Provided administrator and target are " + "the same object."); } if (admin.getPackageName().equals(target.getPackageName())) { throw new IllegalArgumentException("Provided administrator and target have " + "the same package name."); } final int callingUserId = mInjector.userHandleGetCallingUserId(); final DevicePolicyData policy = getUserData(callingUserId); final DeviceAdminInfo incomingDeviceInfo = findAdmin(target, callingUserId, /* throwForMissingPermission= */ true); checkActiveAdminPrecondition(target, incomingDeviceInfo, policy); final long id = mInjector.binderClearCallingIdentity(); try { //STOPSHIP add support for COMP, DO, edge cases when device is rebooted/work mode off, //transfer callbacks and broadcast if (isProfileOwner(admin, callingUserId)) { transferProfileOwner(admin, target, callingUserId); } } finally { mInjector.binderRestoreCallingIdentity(id); } } /** * Transfers the profile owner for user with id profileOwnerUserId from admin to target. */ private void transferProfileOwner(ComponentName admin, ComponentName target, int profileOwnerUserId) { synchronized (this) { transferActiveAdminUncheckedLocked(target, admin, profileOwnerUserId); mOwners.transferProfileOwner(target, profileOwnerUserId); Slog.i(LOG_TAG, "Profile owner set: " + target + " on user " + profileOwnerUserId); mOwners.writeProfileOwner(profileOwnerUserId); mDeviceAdminServiceController.startServiceForOwner( target.getPackageName(), profileOwnerUserId, "transfer-profile-owner"); } } }
services/devicepolicy/java/com/android/server/devicepolicy/Owners.java +11 −0 Original line number Diff line number Diff line Loading @@ -277,6 +277,17 @@ class Owners { } } void transferProfileOwner(ComponentName target, int userId) { synchronized (mLock) { final OwnerInfo ownerInfo = mProfileOwners.get(userId); final OwnerInfo newOwnerInfo = new OwnerInfo(target.getPackageName(), target, ownerInfo.userRestrictionsMigrated, ownerInfo.remoteBugreportUri, ownerInfo.remoteBugreportHash); mProfileOwners.put(userId, newOwnerInfo); pushToPackageManagerLocked(); } } ComponentName getProfileOwnerComponent(int userId) { synchronized (mLock) { OwnerInfo profileOwner = mProfileOwners.get(userId); Loading