diff options
7 files changed, 144 insertions, 47 deletions
diff --git a/api/current.txt b/api/current.txt index ed0c6a982b70..484ca48bb95b 100644 --- a/api/current.txt +++ b/api/current.txt @@ -6322,6 +6322,7 @@ package android.app.admin { method public void onReceive(android.content.Context, android.content.Intent); method public void onSecurityLogsAvailable(android.content.Context, android.content.Intent); method public void onSystemUpdatePending(android.content.Context, android.content.Intent, long); + method public void onTransferOwnershipComplete(android.content.Context, android.os.PersistableBundle); method public void onUserAdded(android.content.Context, android.content.Intent, android.os.UserHandle); method public void onUserRemoved(android.content.Context, android.content.Intent, android.os.UserHandle); field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED"; @@ -6339,6 +6340,7 @@ package android.app.admin { field public static final java.lang.String DEVICE_ADMIN_META_DATA = "android.app.device_admin"; field public static final java.lang.String EXTRA_DISABLE_WARNING = "android.app.extra.DISABLE_WARNING"; field public static final java.lang.String EXTRA_LOCK_TASK_PACKAGE = "android.app.extra.LOCK_TASK_PACKAGE"; + field public static final java.lang.String EXTRA_TRANSFER_OWNER_ADMIN_EXTRAS_BUNDLE = "android.app.extra.TRANSFER_OWNER_ADMIN_EXTRAS_BUNDLE"; } public class DeviceAdminService extends android.app.Service { @@ -6531,6 +6533,7 @@ package android.app.admin { method public void setUserIcon(android.content.ComponentName, android.graphics.Bitmap); method public boolean stopUser(android.content.ComponentName, android.os.UserHandle); method public boolean switchUser(android.content.ComponentName, android.os.UserHandle); + method public void transferOwnership(android.content.ComponentName, android.content.ComponentName, android.os.PersistableBundle); method public void uninstallAllUserCaCerts(android.content.ComponentName); method public void uninstallCaCert(android.content.ComponentName, byte[]); method public void wipeData(int); @@ -6540,6 +6543,7 @@ package android.app.admin { field public static final java.lang.String ACTION_DEVICE_ADMIN_SERVICE = "android.app.action.DEVICE_ADMIN_SERVICE"; field public static final java.lang.String ACTION_DEVICE_OWNER_CHANGED = "android.app.action.DEVICE_OWNER_CHANGED"; field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED"; + field public static final java.lang.String ACTION_PROFILE_OWNER_CHANGED = "android.app.action.PROFILE_OWNER_CHANGED"; field public static final java.lang.String ACTION_PROVISIONING_SUCCESSFUL = "android.app.action.PROVISIONING_SUCCESSFUL"; field public static final java.lang.String ACTION_PROVISION_MANAGED_DEVICE = "android.app.action.PROVISION_MANAGED_DEVICE"; field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE"; diff --git a/core/java/android/app/admin/DeviceAdminReceiver.java b/core/java/android/app/admin/DeviceAdminReceiver.java index 2e697ac0e6bb..aa05b7630c9d 100644 --- a/core/java/android/app/admin/DeviceAdminReceiver.java +++ b/core/java/android/app/admin/DeviceAdminReceiver.java @@ -29,10 +29,14 @@ import android.content.Context; import android.content.Intent; import android.net.Uri; import android.os.Bundle; +import android.os.PersistableBundle; import android.os.Process; import android.os.UserHandle; import android.security.KeyChain; +import libcore.util.NonNull; +import libcore.util.Nullable; + import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -438,6 +442,31 @@ public class DeviceAdminReceiver extends BroadcastReceiver { // TO DO: describe syntax. public static final String DEVICE_ADMIN_META_DATA = "android.app.device_admin"; + /** + * Broadcast action: notify the newly transferred administrator that the transfer + * from the original administrator was successful. + * + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_TRANSFER_OWNERSHIP_COMPLETE = + "android.app.action.TRANSFER_OWNERSHIP_COMPLETE"; + + /** + * A {@link android.os.Parcelable} extra of type {@link android.os.PersistableBundle} that + * allows a mobile device management application to pass data to the management application + * instance after owner transfer. + * + * <p> + * If the transfer is successful, the new device owner receives the data in + * {@link DeviceAdminReceiver#onTransferOwnershipComplete(Context, PersistableBundle)}. + * The bundle is not changed during the ownership transfer. + * + * @see DevicePolicyManager#transferOwnership(ComponentName, ComponentName, PersistableBundle) + */ + public static final String EXTRA_TRANSFER_OWNER_ADMIN_EXTRAS_BUNDLE = + "android.app.extra.TRANSFER_OWNER_ADMIN_EXTRAS_BUNDLE"; + private DevicePolicyManager mManager; private ComponentName mWho; @@ -860,6 +889,20 @@ public class DeviceAdminReceiver extends BroadcastReceiver { } /** + * Called on the newly assigned owner (either device owner or profile owner) when the ownership + * transfer has completed successfully. + * + * <p> The {@code bundle} parameter allows the original owner to pass data + * to the new one. + * + * @param context the running context as per {@link #onReceive} + * @param bundle the data to be passed to the new owner + */ + public void onTransferOwnershipComplete(@NonNull Context context, + @Nullable PersistableBundle bundle) { + } + + /** * Intercept standard device administrator broadcasts. Implementations * should not override this method; it is better to implement the * convenience callbacks for each action. @@ -921,6 +964,10 @@ public class DeviceAdminReceiver extends BroadcastReceiver { onUserAdded(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER)); } else if (ACTION_USER_REMOVED.equals(action)) { onUserRemoved(context, intent, intent.getParcelableExtra(Intent.EXTRA_USER)); + } else if (ACTION_TRANSFER_OWNERSHIP_COMPLETE.equals(action)) { + PersistableBundle bundle = + intent.getParcelableExtra(EXTRA_TRANSFER_OWNER_ADMIN_EXTRAS_BUNDLE); + onTransferOwnershipComplete(context, bundle); } } } diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java index 76c078ec9c05..ab85fdce6ce8 100644 --- a/core/java/android/app/admin/DevicePolicyManager.java +++ b/core/java/android/app/admin/DevicePolicyManager.java @@ -1124,6 +1124,7 @@ public class DevicePolicyManager { * * This broadcast is sent only to the primary user. * @see #ACTION_PROVISION_MANAGED_DEVICE + * @see DevicePolicyManager#transferOwnership(ComponentName, ComponentName, PersistableBundle) */ @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) public static final String ACTION_DEVICE_OWNER_CHANGED @@ -1709,6 +1710,16 @@ public class DevicePolicyManager { public static final int ID_TYPE_MEID = 8; /** + * Broadcast action: sent when the profile owner is set, changed or cleared. + * + * This broadcast is sent only to the user managed by the new profile owner. + * @see DevicePolicyManager#transferOwnership(ComponentName, ComponentName, PersistableBundle) + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_PROFILE_OWNER_CHANGED = + "android.app.action.PROFILE_OWNER_CHANGED"; + + /** * Return true if the given administrator component is currently active (enabled) in the system. * * @param admin The administrator component to check for. @@ -8997,41 +9008,34 @@ public class DevicePolicyManager { } } - //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. + * Changes the current administrator to another one. 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: + * <p>Depending on the current administrator (device owner, 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 + * <p>Use the {@code bundle} parameter to pass data to the new administrator. The parameters + * will be received in the + * {@link DeviceAdminReceiver#onTransferOwnershipComplete(Context, PersistableBundle)} callback. + * + * @param admin which {@link DeviceAdminReceiver} this request is associated with + * @param target which {@link DeviceAdminReceiver} we want the new administrator to be + * @param bundle data to be sent to the new administrator + * @throws SecurityException if {@code admin} is not a device owner nor a profile owner + * @throws IllegalArgumentException if {@code admin} or {@code target} is {@code null}, + * both are components in the same package or {@code target} is not an active admin */ - public void transferOwner(@NonNull ComponentName admin, @NonNull ComponentName target, + public void transferOwnership(@NonNull ComponentName admin, @NonNull ComponentName target, PersistableBundle bundle) { - throwIfParentInstance("transferOwner"); + throwIfParentInstance("transferOwnership"); try { - mService.transferOwner(admin, target, bundle); + mService.transferOwnership(admin, target, bundle); } catch (RemoteException re) { throw re.rethrowFromSystemServer(); } diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl index 5916a629f2e6..1d8ddeebcc26 100644 --- a/core/java/android/app/admin/IDevicePolicyManager.aidl +++ b/core/java/android/app/admin/IDevicePolicyManager.aidl @@ -387,5 +387,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); + void transferOwnership(in ComponentName admin, in ComponentName target, in PersistableBundle bundle); } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 00e3a4a68f78..060d66465728 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -572,6 +572,10 @@ <protected-broadcast android:name="android.intent.action.GET_RESTRICTION_ENTRIES" /> <protected-broadcast android:name="android.telephony.euicc.action.OTA_STATUS_CHANGED" /> + <!-- Added in P --> + <protected-broadcast android:name="android.app.action.PROFILE_OWNER_CHANGED" /> + <protected-broadcast android:name="android.app.action.TRANSFER_OWNER_COMPLETE" /> + <!-- ====================================================================== --> <!-- RUNTIME PERMISSIONS --> <!-- ====================================================================== --> diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java index c1e95ebeddf2..29ac4cec29e1 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java @@ -64,7 +64,7 @@ abstract class BaseIDevicePolicyManager extends IDevicePolicyManager.Stub { public void setSystemSetting(ComponentName who, String setting, String value){} - public void transferOwner(ComponentName admin, ComponentName target, PersistableBundle bundle) {} + public void transferOwnership(ComponentName admin, ComponentName target, PersistableBundle bundle) {} public boolean generateKeyPair(ComponentName who, String callerPackage, String algorithm, ParcelableKeyGenParameterSpec keySpec, int idAttestationFlags, diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index f0681e9eb32e..3592fc0b082f 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -20,6 +20,7 @@ import static android.Manifest.permission.BIND_DEVICE_ADMIN; import static android.Manifest.permission.MANAGE_CA_CERTIFICATES; import static android.app.ActivityManager.LOCK_TASK_MODE_NONE; import static android.app.ActivityManager.USER_OP_SUCCESS; +import static android.app.admin.DeviceAdminReceiver.EXTRA_TRANSFER_OWNER_ADMIN_EXTRAS_BUNDLE; import static android.app.admin.DevicePolicyManager.ACTION_PROVISION_MANAGED_USER; import static android.app.admin.DevicePolicyManager.CODE_ACCOUNTS_NOT_EMPTY; import static android.app.admin.DevicePolicyManager.CODE_ADD_MANAGED_PROFILE_DISALLOWED; @@ -154,7 +155,6 @@ import android.provider.ContactsContract.QuickContact; import android.provider.ContactsInternal; import android.provider.Settings; import android.provider.Settings.Global; -import android.security.Credentials; import android.security.IKeyChainAliasCallback; import android.security.IKeyChainService; import android.security.KeyChain; @@ -6506,13 +6506,36 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } - synchronized void sendDeviceOwnerCommand(String action, Bundle extras) { - Intent intent = new Intent(action); - intent.setComponent(mOwners.getDeviceOwnerComponent()); + void sendDeviceOwnerCommand(String action, Bundle extras) { + int deviceOwnerUserId; + ComponentName deviceOwnerComponent; + synchronized (this) { + deviceOwnerUserId = mOwners.getDeviceOwnerUserId(); + deviceOwnerComponent = mOwners.getDeviceOwnerComponent(); + } + sendActiveAdminCommand(action, extras, deviceOwnerUserId, + deviceOwnerComponent); + } + + private void sendProfileOwnerCommand(String action, Bundle extras, int userHandle) { + sendActiveAdminCommand(action, extras, userHandle, + mOwners.getProfileOwnerComponent(userHandle)); + } + + private void sendActiveAdminCommand(String action, Bundle extras, + int userHandle, ComponentName receiverComponent) { + final Intent intent = new Intent(action); + intent.setComponent(receiverComponent); if (extras != null) { intent.putExtras(extras); } - mContext.sendBroadcastAsUser(intent, UserHandle.of(mOwners.getDeviceOwnerUserId())); + mContext.sendBroadcastAsUser(intent, UserHandle.of(userHandle)); + } + + private void sendOwnerChangedBroadcast(String broadcast, int userId) { + final Intent intent = new Intent(broadcast) + .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + mContext.sendBroadcastAsUser(intent, UserHandle.of(userId)); } private synchronized String getDeviceOwnerRemoteBugreportUri() { @@ -6890,10 +6913,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { ident = mInjector.binderClearCallingIdentity(); try { // TODO Send to system too? - mContext.sendBroadcastAsUser( - new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED) - .addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND), - UserHandle.of(userId)); + sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED, userId); } finally { mInjector.binderRestoreCallingIdentity(ident); } @@ -7044,9 +7064,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { try { clearDeviceOwnerLocked(admin, deviceOwnerUserId); removeActiveAdminLocked(deviceOwnerComponent, deviceOwnerUserId); - Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED); - intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); - mContext.sendBroadcastAsUser(intent, UserHandle.of(deviceOwnerUserId)); + sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED, + deviceOwnerUserId); } finally { mInjector.binderRestoreCallingIdentity(ident); } @@ -7131,6 +7150,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { ensureUnknownSourcesRestrictionForProfileOwnerLocked(userHandle, admin, true /* newOwner */); } + sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED, + userHandle); } finally { mInjector.binderRestoreCallingIdentity(id); } @@ -7159,6 +7180,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { try { clearProfileOwnerLocked(admin, userId); removeActiveAdminLocked(who, userId); + sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED, + userId); } finally { mInjector.binderRestoreCallingIdentity(ident); } @@ -11847,9 +11870,9 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } //TODO: Add callback information to the javadoc once it is completed. - //TODO: Make transferOwner atomic. + //TODO: Make transferOwnership atomic. @Override - public void transferOwner(ComponentName admin, ComponentName target, PersistableBundle bundle) { + public void transferOwnership(ComponentName admin, ComponentName target, PersistableBundle bundle) { if (!mHasFeature) { return; } @@ -11877,13 +11900,12 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { final long id = mInjector.binderClearCallingIdentity(); try { - //STOPSHIP add support for COMP, edge cases when device is rebooted/work mode off, - //transfer callbacks and broadcast + //STOPSHIP add support for COMP, edge cases when device is rebooted/work mode off synchronized (this) { if (isProfileOwner(admin, callingUserId)) { - transferProfileOwnerLocked(admin, target, callingUserId); + transferProfileOwnerLocked(admin, target, callingUserId, bundle); } else if (isDeviceOwner(admin, callingUserId)) { - transferDeviceOwnerLocked(admin, target, callingUserId); + transferDeviceOwnerLocked(admin, target, callingUserId, bundle); } } } finally { @@ -11895,24 +11917,40 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { * Transfers the profile owner for user with id profileOwnerUserId from admin to target. */ private void transferProfileOwnerLocked(ComponentName admin, ComponentName target, - int profileOwnerUserId) { + int profileOwnerUserId, PersistableBundle bundle) { 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"); + sendProfileOwnerCommand(DeviceAdminReceiver.ACTION_TRANSFER_OWNERSHIP_COMPLETE, + getTransferOwnerAdminExtras(bundle), profileOwnerUserId); + sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_PROFILE_OWNER_CHANGED, + profileOwnerUserId); } /** * Transfers the device owner for user with id userId from admin to target. */ - private void transferDeviceOwnerLocked(ComponentName admin, ComponentName target, int userId) { + private void transferDeviceOwnerLocked(ComponentName admin, ComponentName target, int userId, + PersistableBundle bundle) { transferActiveAdminUncheckedLocked(target, admin, userId); mOwners.transferDeviceOwner(target); Slog.i(LOG_TAG, "Device owner set: " + target + " on user " + userId); mOwners.writeDeviceOwner(); mDeviceAdminServiceController.startServiceForOwner( target.getPackageName(), userId, "transfer-device-owner"); + sendDeviceOwnerCommand(DeviceAdminReceiver.ACTION_TRANSFER_OWNERSHIP_COMPLETE, + getTransferOwnerAdminExtras(bundle)); + sendOwnerChangedBroadcast(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED, userId); + } + + private Bundle getTransferOwnerAdminExtras(PersistableBundle bundle) { + Bundle extras = new Bundle(); + if (bundle != null) { + extras.putParcelable(EXTRA_TRANSFER_OWNER_ADMIN_EXTRAS_BUNDLE, bundle); + } + return extras; } } |