Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 20118f18 authored by Julia Reynolds's avatar Julia Reynolds
Browse files

Allow the device initializer to perform user setup tasks.

A device initializer is an application that is allowed to run
during user provisioning on device owner devices. During
device provisioning (or, user provisioning of the first user
of the device), a device initializer is granted device owner
permissions. During secondary user provisioning, a device
initializer is granted profile owner permissions. Once
provisioning is complete for a user, all elevated permissions
are removed from the device initializer and the device admin
component of the app is disabled.

Bug: 19230954
Change-Id: Ib6725fb3b09bb21e4198a5dc0b445ccebb40b27e
parent d5fe9f60
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -5429,6 +5429,7 @@ package android.app.admin {
    method public void onPasswordFailed(android.content.Context, android.content.Intent);
    method public void onPasswordSucceeded(android.content.Context, android.content.Intent);
    method public void onProfileProvisioningComplete(android.content.Context, android.content.Intent);
    method public void onReadyForUserInitialization(android.content.Context, android.content.Intent);
    method public void onReceive(android.content.Context, android.content.Intent);
    field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED";
    field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
@@ -5440,6 +5441,7 @@ package android.app.admin {
    field public static final java.lang.String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED";
    field public static final java.lang.String ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
    field public static final java.lang.String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE";
    field public static final java.lang.String ACTION_READY_FOR_USER_INITIALIZATION = "android.app.action.READY_FOR_USER_INITIALIZATION";
    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";
@@ -5451,6 +5453,7 @@ package android.app.admin {
    method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
    method public void addUserRestriction(android.content.ComponentName, java.lang.String);
    method public void clearCrossProfileIntentFilters(android.content.ComponentName);
    method public void clearDeviceInitializerApp();
    method public void clearDeviceOwnerApp(java.lang.String);
    method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
    method public void clearUserRestriction(android.content.ComponentName, java.lang.String);
@@ -5489,11 +5492,13 @@ package android.app.admin {
    method public int getStorageEncryptionStatus();
    method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
    method public boolean hasGrantedPolicy(android.content.ComponentName, int);
    method public boolean hasUserSetupCompleted();
    method public boolean installCaCert(android.content.ComponentName, byte[]);
    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
    method public boolean isActivePasswordSufficient();
    method public boolean isAdminActive(android.content.ComponentName);
    method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
    method public boolean isDeviceInitializerApp(java.lang.String);
    method public boolean isDeviceOwnerApp(java.lang.String);
    method public boolean isLockTaskPermitted(java.lang.String);
    method public boolean isMasterVolumeMuted(android.content.ComponentName);
@@ -5510,6 +5515,7 @@ package android.app.admin {
    method public void setAutoTimeRequired(android.content.ComponentName, boolean);
    method public void setCameraDisabled(android.content.ComponentName, boolean);
    method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
    method public boolean setDeviceInitializer(android.content.ComponentName, android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
    method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
    method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
    method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
@@ -5536,6 +5542,7 @@ package android.app.admin {
    method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
    method public int setStorageEncryption(android.content.ComponentName, boolean);
    method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
    method public boolean setUserEnabled(android.content.ComponentName);
    method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
    method public void uninstallAllUserCaCerts(android.content.ComponentName);
    method public void uninstallCaCert(android.content.ComponentName, byte[]);
@@ -5557,6 +5564,10 @@ package android.app.admin {
    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION";
    field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
    field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
    field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
+12 −0
Original line number Diff line number Diff line
@@ -5523,6 +5523,7 @@ package android.app.admin {
    method public void onPasswordFailed(android.content.Context, android.content.Intent);
    method public void onPasswordSucceeded(android.content.Context, android.content.Intent);
    method public void onProfileProvisioningComplete(android.content.Context, android.content.Intent);
    method public void onReadyForUserInitialization(android.content.Context, android.content.Intent);
    method public void onReceive(android.content.Context, android.content.Intent);
    field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLED = "android.app.action.DEVICE_ADMIN_DISABLED";
    field public static final java.lang.String ACTION_DEVICE_ADMIN_DISABLE_REQUESTED = "android.app.action.DEVICE_ADMIN_DISABLE_REQUESTED";
@@ -5534,6 +5535,7 @@ package android.app.admin {
    field public static final java.lang.String ACTION_PASSWORD_FAILED = "android.app.action.ACTION_PASSWORD_FAILED";
    field public static final java.lang.String ACTION_PASSWORD_SUCCEEDED = "android.app.action.ACTION_PASSWORD_SUCCEEDED";
    field public static final java.lang.String ACTION_PROFILE_PROVISIONING_COMPLETE = "android.app.action.PROFILE_PROVISIONING_COMPLETE";
    field public static final java.lang.String ACTION_READY_FOR_USER_INITIALIZATION = "android.app.action.READY_FOR_USER_INITIALIZATION";
    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";
@@ -5545,6 +5547,7 @@ package android.app.admin {
    method public void addPersistentPreferredActivity(android.content.ComponentName, android.content.IntentFilter, android.content.ComponentName);
    method public void addUserRestriction(android.content.ComponentName, java.lang.String);
    method public void clearCrossProfileIntentFilters(android.content.ComponentName);
    method public void clearDeviceInitializerApp();
    method public void clearDeviceOwnerApp(java.lang.String);
    method public void clearPackagePersistentPreferredActivities(android.content.ComponentName, java.lang.String);
    method public void clearProfileOwner(android.content.ComponentName);
@@ -5561,6 +5564,7 @@ package android.app.admin {
    method public boolean getCrossProfileCallerIdDisabled(android.content.ComponentName);
    method public java.util.List<java.lang.String> getCrossProfileWidgetProviders(android.content.ComponentName);
    method public int getCurrentFailedPasswordAttempts();
    method public java.lang.String getDeviceInitializerApp();
    method public java.lang.String getDeviceOwner();
    method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
    method public int getKeyguardDisabledFeatures(android.content.ComponentName);
@@ -5589,11 +5593,13 @@ package android.app.admin {
    method public int getStorageEncryptionStatus();
    method public boolean hasCaCertInstalled(android.content.ComponentName, byte[]);
    method public boolean hasGrantedPolicy(android.content.ComponentName, int);
    method public boolean hasUserSetupCompleted();
    method public boolean installCaCert(android.content.ComponentName, byte[]);
    method public boolean installKeyPair(android.content.ComponentName, java.security.PrivateKey, java.security.cert.Certificate, java.lang.String);
    method public boolean isActivePasswordSufficient();
    method public boolean isAdminActive(android.content.ComponentName);
    method public boolean isApplicationHidden(android.content.ComponentName, java.lang.String);
    method public boolean isDeviceInitializerApp(java.lang.String);
    method public boolean isDeviceOwnerApp(java.lang.String);
    method public boolean isLockTaskPermitted(java.lang.String);
    method public boolean isMasterVolumeMuted(android.content.ComponentName);
@@ -5611,6 +5617,7 @@ package android.app.admin {
    method public void setAutoTimeRequired(android.content.ComponentName, boolean);
    method public void setCameraDisabled(android.content.ComponentName, boolean);
    method public void setCrossProfileCallerIdDisabled(android.content.ComponentName, boolean);
    method public boolean setDeviceInitializer(android.content.ComponentName, android.content.ComponentName, java.lang.String) throws java.lang.IllegalArgumentException, java.lang.IllegalStateException;
    method public void setGlobalSetting(android.content.ComponentName, java.lang.String, java.lang.String);
    method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
    method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
@@ -5637,6 +5644,7 @@ package android.app.admin {
    method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
    method public int setStorageEncryption(android.content.ComponentName, boolean);
    method public void setUninstallBlocked(android.content.ComponentName, java.lang.String, boolean);
    method public boolean setUserEnabled(android.content.ComponentName);
    method public boolean switchUser(android.content.ComponentName, android.os.UserHandle);
    method public void uninstallAllUserCaCerts(android.content.ComponentName);
    method public void uninstallCaCert(android.content.ComponentName, byte[]);
@@ -5660,6 +5668,10 @@ package android.app.admin {
    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_COOKIE_HEADER";
    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION";
    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME";
    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
    field public static final java.lang.String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION = "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION";
    field public static final java.lang.String EXTRA_PROVISIONING_EMAIL_ADDRESS = "android.app.extra.PROVISIONING_EMAIL_ADDRESS";
    field public static final java.lang.String EXTRA_PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED = "android.app.extra.PROVISIONING_LEAVE_ALL_SYSTEM_APPS_ENABLED";
    field public static final java.lang.String EXTRA_PROVISIONING_LOCALE = "android.app.extra.PROVISIONING_LOCALE";
+53 −9
Original line number Diff line number Diff line
@@ -215,7 +215,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
     * <p>A device admin application which listens to this intent can find out if the device was
     * provisioned for the device owner or profile owner case by calling respectively
     * {@link android.app.admin.DevicePolicyManager#isDeviceOwnerApp} and
     * {@link android.app.admin.DevicePolicyManager#isProfileOwnerApp}.
     * {@link android.app.admin.DevicePolicyManager#isProfileOwnerApp}. You will generally handle
     * this in {@link DeviceAdminReceiver#onProfileProvisioningComplete}.
     *
     * <p>Input: Nothing.</p>
     * <p>Output: Nothing</p>
@@ -224,6 +225,23 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
    public static final String ACTION_PROFILE_PROVISIONING_COMPLETE =
            "android.app.action.PROFILE_PROVISIONING_COMPLETE";

    /**
     * Broadcast Action: This broadcast is sent to indicate that the system is ready for the device
     * initializer to perform user setup tasks. This is only applicable to devices managed by a
     * device owner app.
     *
     * <p>The broadcast will be limited to the {@link DeviceAdminReceiver} component specified in
     * the (@link DevicePolicyManager#EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME) field
     * of the original intent or NFC bump that started the provisioning process. You will generally
     * handle this in {@link DeviceAdminReceiver#onReadyForUserInitialization}.
     *
     * <p>Input: Nothing.</p>
     * <p>Output: Nothing</p>
     */
    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
    public static final String ACTION_READY_FOR_USER_INITIALIZATION =
            "android.app.action.READY_FOR_USER_INITIALIZATION";

    /** @hide */
    public static final String ACTION_CHOOSE_PRIVATE_KEY_ALIAS = "android.app.action.CHOOSE_PRIVATE_KEY_ALIAS";

@@ -382,20 +400,20 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
    /**
     * Called when provisioning of a managed profile or managed device has completed successfully.
     *
     * <p> As a prerequisit for the execution of this callback the (@link DeviceAdminReceiver} has
     * <p> As a prerequisite for the execution of this callback the {@link DeviceAdminReceiver} has
     * to declare an intent filter for {@link #ACTION_PROFILE_PROVISIONING_COMPLETE}.
     * Its component must also be specified in the {@link DevicePolicyManager#EXTRA_DEVICE_ADMIN}
     * of the {@link DevicePolicyManager#ACTION_PROVISION_MANAGED_PROFILE} intent that started the
     * managed provisioning.
     *
     * <p>When provisioning is complete, the managed profile is hidden until the profile owner
     * calls {DevicePolicyManager#setProfileEnabled(ComponentName admin)}. Typically a profile
     * owner will enable the profile when it has finished any additional setup such as adding an
     * account by using the {@link AccountManager} and calling apis to bring the profile into the
     * desired state.
     * <p>When provisioning of a managed profile is complete, the managed profile is hidden until
     * the profile owner calls {DevicePolicyManager#setProfileEnabled(ComponentName admin)}.
     * Typically a profile owner will enable the profile when it has finished any additional setup
     * such as adding an account by using the {@link AccountManager} and calling apis to bring the
     * profile into the desired state.
     *
     * <p> Note that provisioning completes without waiting for any server interactions, so the
     * profile owner needs to wait for data to be available if required (e.g android device ids or
     * profile owner needs to wait for data to be available if required (e.g. android device ids or
     * other data that is set as a result of server interactions).
     *
     * @param context The running context as per {@link #onReceive}.
@@ -404,6 +422,30 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
    public void onProfileProvisioningComplete(Context context, Intent intent) {
    }

    /**
     * Called during provisioning of a managed device to allow the device initializer to perform
     * user setup steps. Only device initializers should override this method.
     *
     * <p> Called when the DeviceAdminReceiver receives a
     * {@link #ACTION_READY_FOR_USER_INITIALIZATION} broadcast. As a prerequisite for the execution
     * of this callback the {@link DeviceAdminReceiver} has
     * to declare an intent filter for {@link #ACTION_READY_FOR_USER_INITIALIZATION}. Only the
     * component specified in the
     * {@link DevicePolicyManager#EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME} field of the
     * original intent or NFC bump that started the provisioning process will receive this callback.
     *
     * <p>It is not assumed that the device initializer is finished when it returns from
     * this call, as it may do additional setup asynchronously. The device initializer must call
     * {DevicePolicyManager#setUserEnabled(ComponentName admin)} when it has finished any additional
     * setup (such as adding an account by using the {@link AccountManager}) in order for the user
     * to be functional.
     *
     * @param context The running context as per {@link #onReceive}.
     * @param intent The received intent as per {@link #onReceive}.
     */
    public void onReadyForUserInitialization(Context context, Intent intent) {
    }

    /**
     * Called when a device is entering lock task mode by a package authorized
     * by {@link DevicePolicyManager#isLockTaskPermitted(String)}
@@ -488,6 +530,8 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
            onLockTaskModeEntering(context, intent, pkg);
        } else if (ACTION_LOCK_TASK_EXITING.equals(action)) {
            onLockTaskModeExiting(context, intent);
        } else if (ACTION_READY_FOR_USER_INITIALIZATION.equals(action)) {
            onReadyForUserInitialization(context, intent);
        }
    }
}
+158 −9

File changed.

Preview size limit exceeded, changes collapsed.

+6 −0
Original line number Diff line number Diff line
@@ -199,4 +199,10 @@ interface IDevicePolicyManager {
    boolean getAutoTimeRequired();

    boolean isRemovingAdmin(in ComponentName adminReceiver, int userHandle);

    boolean setUserEnabled(in ComponentName who);
    boolean isDeviceInitializer(String packageName);
    void clearDeviceInitializer(String packageName);
    boolean setDeviceInitializer(in ComponentName who, in ComponentName initializer, String initializerName);
    String getDeviceInitializer();
}
Loading