OSDN Git Service

Call PROFILE/DEVICE_OWNER_CHANGED broadcast and onTransferCompleted callback upon...
authorarangelov <arangelov@google.com>
Wed, 20 Dec 2017 20:26:46 +0000 (20:26 +0000)
committerarangelov <arangelov@google.com>
Wed, 10 Jan 2018 21:07:44 +0000 (21:07 +0000)
Test: cts-tradefed run cts-dev --module DevicePolicyManager --test com.android.cts.devicepolicy.MixedProfileOwnerHostSideTransferTest#testTransferOwnerChangedBroadcast
Test: cts-tradefed run cts-dev --module DevicePolicyManager --test com.android.cts.devicepolicy.MixedProfileOwnerHostSideTransferTest#testTransferCompleteCallback
Test: cts-tradefed run cts-dev --module DevicePolicyManager --test com.android.cts.devicepolicy.MixedDeviceOwnerHostSideTransferTest#testTransferOwnerChangedBroadcast
Test: cts-tradefed run cts-dev --module DevicePolicyManager --test com.android.cts.devicepolicy.MixedDeviceOwnerHostSideTransferTest#testTransferCompleteCallback
Bug: 69542936
Bug: 69543044
Change-Id: Ifbe3ac0029794eba185e538e5a490073d5309f0b

api/current.txt
core/java/android/app/admin/DeviceAdminReceiver.java
core/java/android/app/admin/DevicePolicyManager.java
core/java/android/app/admin/IDevicePolicyManager.aidl
core/res/AndroidManifest.xml
services/devicepolicy/java/com/android/server/devicepolicy/BaseIDevicePolicyManager.java
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java

index d8deef3..2cc7495 100644 (file)
@@ -6297,6 +6297,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";
@@ -6314,6 +6315,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 {
@@ -6506,6 +6508,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);
@@ -6515,6 +6518,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";
index 2e697ac..aa05b76 100644 (file)
@@ -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);
         }
     }
 }
index 0b74741..e46e1cc 100644 (file)
@@ -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.
@@ -8990,41 +9001,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();
         }
index 5916a62..1d8ddee 100644 (file)
@@ -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);
 }
index 52bfcde..72bcdf6 100644 (file)
     <!-- Made protected in P (was introduced in JB-MR2) -->
     <protected-broadcast android:name="android.intent.action.GET_RESTRICTION_ENTRIES" />
 
+    <!-- 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                           -->
     <!-- ====================================================================== -->
index c1e95eb..29ac4ce 100644 (file)
@@ -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,
index 11fce4d..6bcb153 100644 (file)
@@ -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);
             }
@@ -11846,9 +11869,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;
         }
@@ -11876,13 +11899,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 {
@@ -11894,24 +11916,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;
     }
 }