Merge "Allow the device initializer to perform user setup tasks."

This commit is contained in:
Julia Reynolds
2015-03-04 19:01:30 +00:00
committed by Android (Google) Code Review
7 changed files with 443 additions and 21 deletions

View File

@@ -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";

View File

@@ -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";

View File

@@ -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";
@@ -245,7 +263,7 @@ public class DeviceAdminReceiver extends BroadcastReceiver {
/** @hide */
public static final String EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE = "android.app.extra.CHOOSE_PRIVATE_KEY_RESPONSE";
/**
/**
* Name under which a DevicePolicy component publishes information
* about itself. This meta-data must reference an XML resource containing
* a device-admin tag.
@@ -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);
}
}
}

View File

@@ -356,6 +356,52 @@ public class DevicePolicyManager {
public static final String EXTRA_PROVISIONING_SKIP_ENCRYPTION =
"android.app.extra.PROVISIONING_SKIP_ENCRYPTION";
/**
* On devices managed by a device owner app, a String representation of a Component name extra
* indicating the component of the application that is temporarily granted device owner
* privileges during device initialization and profile owner privileges during secondary user
* initialization.
*
* <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
* provisioning via an NFC bump.
* @see ComponentName#unflattenFromString()
*/
public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME
= "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_COMPONENT_NAME";
/**
* A String extra holding an http url that specifies the download location of the device
* initializer package. When not provided it is assumed that the device initializer package is
* already installed.
*
* <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION
= "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION";
/**
* A String extra holding a http cookie header which should be used in the http request to the
* url specified in {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}.
*
* <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER
= "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_COOKIE_HEADER";
/**
* A String extra holding the SHA-1 checksum of the file at download location specified in
* {@link #EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_DOWNLOAD_LOCATION}. If this doesn't
* match the file at the download location an error will be shown to the user and the user will
* be asked to factory reset the device.
*
* <p>Use in an NFC record with {@link #MIME_TYPE_PROVISIONING_NFC} that starts device owner
* provisioning via an NFC bump.
*/
public static final String EXTRA_PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM
= "android.app.extra.PROVISIONING_DEVICE_INITIALIZER_PACKAGE_CHECKSUM";
/**
* This MIME type is used for starting the Device Owner provisioning.
*
@@ -2381,6 +2427,112 @@ public class DevicePolicyManager {
return null;
}
/**
* Sets the given component as the device initializer. The package must already be installed and
* set as an active device administrator, and there must not be an existing device initializer,
* for this call to succeed. This method can only be called by an app holding the
* MANAGE_DEVICE_ADMINS permission before the device is provisioned or by a device owner app. A
* device initializer app is granted device owner privileges during device initialization and
* profile owner privileges during secondary user initialization.
* @param who Which {@link DeviceAdminReceiver} this request is associated with, or null if not
* called by the device owner.
* @param initializer Which {@link DeviceAdminReceiver} to make device initializer.
* @param initializerName The user-visible name of the device initializer.
* @return whether the package was successfully registered as the device initializer.
* @throws IllegalArgumentException if the package name is null or invalid
* @throws IllegalStateException if the caller is not device owner or the device has
* already been provisioned or a device initializer already exists.
*/
public boolean setDeviceInitializer(ComponentName who, ComponentName initializer,
String initializerName) throws IllegalArgumentException, IllegalStateException {
if (mService != null) {
try {
return mService.setDeviceInitializer(who, initializer, initializerName);
} catch (RemoteException re) {
Log.w(TAG, "Failed to set device initializer");
}
}
return false;
}
/**
* Used to determine if a particular package has been registered as the device initializer.
*
* @param packageName the package name of the app, to compare with the registered device
* initializer app, if any.
* @return whether or not the caller is registered as the device initializer app.
*/
public boolean isDeviceInitializerApp(String packageName) {
if (mService != null) {
try {
return mService.isDeviceInitializer(packageName);
} catch (RemoteException re) {
Log.w(TAG, "Failed to check device initializer");
}
}
return false;
}
/**
* Clears the current device initializer. The caller must be the device initializer.
*
* This function should be used cautiously as once it is called it cannot
* be undone.
*/
public void clearDeviceInitializerApp() {
if (mService != null) {
try {
mService.clearDeviceInitializer(mContext.getPackageName());
} catch (RemoteException re) {
Log.w(TAG, "Failed to clear device initializer");
}
}
}
/**
* @hide
* Gets the device initializer of the system.
*
* @return the package name of the device initializer.
*/
@SystemApi
public String getDeviceInitializerApp() {
if (mService != null) {
try {
return mService.getDeviceInitializer();
} catch (RemoteException re) {
Log.w(TAG, "Failed to get device initializer");
}
}
return null;
}
/**
* Sets the enabled state of the user. A user should be enabled only once it is ready to
* be used.
*
* <p>Device initializer must call this method to mark the user as functional.
* Only the device initializer agent can call this.
*
* <p>When the user is enabled, if the device initializer is not also the device owner, the
* device initializer will no longer have elevated permissions to call methods in this class.
* Additionally, it will be removed as an active administrator and its
* {@link DeviceAdminReceiver} will be disabled.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @return whether the user is now enabled.
*/
public boolean setUserEnabled(ComponentName admin) {
if (mService != null) {
try {
return mService.setUserEnabled(admin);
} catch (RemoteException e) {
Log.w(TAG, "Failed talking with device policy service", e);
}
}
return false;
}
/**
* @hide
* @deprecated Use #ACTION_SET_PROFILE_OWNER
@@ -2434,7 +2586,6 @@ public class DevicePolicyManager {
}
/**
* @hide
* Checks if the user was already setup.
*/
public boolean hasUserSetupCompleted() {
@@ -3119,8 +3270,7 @@ public class DevicePolicyManager {
}
/**
* Called by a profile or device owner to set a user restriction specified
* by the key.
* Called by a profile or device owner to set a user restriction specified by the key.
* <p>
* The calling device admin must be a profile or device owner; if it is not,
* a security exception will be thrown.
@@ -3141,8 +3291,7 @@ public class DevicePolicyManager {
}
/**
* Called by a profile or device owner to clear a user restriction specified
* by the key.
* Called by a profile or device owner to clear a user restriction specified by the key.
* <p>
* The calling device admin must be a profile or device owner; if it is not,
* a security exception will be thrown.
@@ -3163,7 +3312,7 @@ public class DevicePolicyManager {
}
/**
* Called by device or profile owner to hide or unhide packages. When a package is hidden it
* Called by profile or device owners to hide or unhide packages. When a package is hidden it
* is unavailable for use, but the data and actual package file remain.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3185,7 +3334,7 @@ public class DevicePolicyManager {
}
/**
* Called by device or profile owner to determine if a package is hidden.
* Called by profile or device owners to determine if a package is hidden.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
* @param packageName The name of the package to retrieve the hidden status of.
@@ -3203,7 +3352,7 @@ public class DevicePolicyManager {
}
/**
* Called by profile or device owner to re-enable a system app that was disabled by default
* Called by profile or device owners to re-enable a system app that was disabled by default
* when the user was initialized.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -3220,7 +3369,7 @@ public class DevicePolicyManager {
}
/**
* Called by profile or device owner to re-enable system apps by intent that were disabled
* Called by profile or device owners to re-enable system apps by intent that were disabled
* by default when the user was initialized.
*
* @param admin Which {@link DeviceAdminReceiver} this request is associated with.

View File

@@ -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();
}

View File

@@ -53,6 +53,7 @@ class DeviceOwner {
private static final String DEVICE_OWNER_XML = "device_owner.xml";
private static final String TAG_DEVICE_OWNER = "device-owner";
private static final String TAG_DEVICE_INITIALIZER = "device-initializer";
private static final String TAG_PROFILE_OWNER = "profile-owner";
private static final String ATTR_NAME = "name";
private static final String ATTR_PACKAGE = "package";
@@ -68,6 +69,9 @@ class DeviceOwner {
// Internal state for the device owner package.
private OwnerInfo mDeviceOwner;
// Internal state for the device initializer package.
private OwnerInfo mDeviceInitializer;
// Internal state for the profile owner packages.
private final HashMap<Integer, OwnerInfo> mProfileOwners = new HashMap<Integer, OwnerInfo>();
@@ -103,6 +107,15 @@ class DeviceOwner {
return owner;
}
/**
* Creates an instance of the device owner object with the device initializer set.
*/
static DeviceOwner createWithDeviceInitializer(String packageName, String ownerName) {
DeviceOwner owner = new DeviceOwner();
owner.mDeviceInitializer = new OwnerInfo(ownerName, packageName);
return owner;
}
/**
* Creates an instance of the device owner object with the profile owner set.
*/
@@ -128,6 +141,26 @@ class DeviceOwner {
mDeviceOwner = null;
}
String getDeviceInitializerPackageName() {
return mDeviceInitializer != null ? mDeviceInitializer.packageName : null;
}
String getDeviceInitializerName() {
return mDeviceInitializer != null ? mDeviceInitializer.name : null;
}
void setDeviceInitializer(String packageName, String ownerName) {
mDeviceInitializer = new OwnerInfo(ownerName, packageName);
}
void clearDeviceInitializer() {
mDeviceInitializer = null;
}
boolean hasDeviceInitializer() {
return mDeviceInitializer != null;
}
void setProfileOwner(ComponentName admin, String ownerName, int userId) {
mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
}
@@ -199,6 +232,10 @@ class DeviceOwner {
String name = parser.getAttributeValue(null, ATTR_NAME);
String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
mDeviceOwner = new OwnerInfo(name, packageName);
} else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
String name = parser.getAttributeValue(null, ATTR_NAME);
String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
mDeviceInitializer = new OwnerInfo(name, packageName);
} else if (tag.equals(TAG_PROFILE_OWNER)) {
String profileOwnerPackageName = parser.getAttributeValue(null, ATTR_PACKAGE);
String profileOwnerName = parser.getAttributeValue(null, ATTR_NAME);
@@ -259,6 +296,16 @@ class DeviceOwner {
out.endTag(null, TAG_DEVICE_OWNER);
}
// Write device initializer tag
if (mDeviceInitializer != null) {
out.startTag(null, TAG_DEVICE_INITIALIZER);
out.attribute(null, ATTR_PACKAGE, mDeviceInitializer.packageName);
if (mDeviceInitializer.name != null) {
out.attribute(null, ATTR_NAME, mDeviceInitializer.name);
}
out.endTag(null, TAG_DEVICE_INITIALIZER);
}
// Write profile owner tags
if (mProfileOwners.size() > 0) {
for (HashMap.Entry<Integer, OwnerInfo> owner : mProfileOwners.entrySet()) {

View File

@@ -1139,13 +1139,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
boolean ownsProfile = (getProfileOwner(userHandle) != null
&& getProfileOwner(userHandle).getPackageName()
.equals(admin.info.getPackageName()));
boolean ownsInitialization = isDeviceInitializer(admin.info.getPackageName())
&& !hasUserSetupCompleted(userHandle);
if (reqPolicy == DeviceAdminInfo.USES_POLICY_DEVICE_OWNER) {
if (ownsDevice) {
if (ownsDevice || (userHandle == UserHandle.USER_OWNER && ownsInitialization)) {
return admin;
}
} else if (reqPolicy == DeviceAdminInfo.USES_POLICY_PROFILE_OWNER) {
if (ownsDevice || ownsProfile) {
if (ownsDevice || ownsProfile || ownsInitialization) {
return admin;
}
} else {
@@ -1899,7 +1901,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return;
}
if (admin.getUid() != Binder.getCallingUid()) {
// If trying to remove device owner, refuse when the caller is not the owner.
// Active device owners must remain active admins.
if (isDeviceOwner(adminReceiver.getPackageName())) {
return;
}
@@ -3865,6 +3867,112 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
@Override
public boolean setDeviceInitializer(ComponentName who, ComponentName initializer,
String ownerName) {
if (!mHasFeature) {
return false;
}
if (initializer == null || !DeviceOwner.isInstalled(
initializer.getPackageName(), mContext.getPackageManager())) {
throw new IllegalArgumentException("Invalid component name " + initializer
+ " for device initializer");
}
synchronized (this) {
enforceCanSetDeviceInitializer(who);
if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
throw new IllegalStateException(
"Trying to set device initializer but device initializer is already set.");
}
if (mDeviceOwner == null) {
// Device owner state does not exist, create it.
mDeviceOwner = DeviceOwner.createWithDeviceInitializer(
initializer.getPackageName(), ownerName);
mDeviceOwner.writeOwnerFile();
return true;
} else {
// Device owner already exists, update it.
mDeviceOwner.setDeviceInitializer(initializer.getPackageName(), ownerName);
mDeviceOwner.writeOwnerFile();
return true;
}
}
}
private void enforceCanSetDeviceInitializer(ComponentName who) {
if (who == null) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
if (hasUserSetupCompleted(UserHandle.USER_OWNER)) {
throw new IllegalStateException(
"Trying to set device initializer but device is already provisioned.");
}
} else {
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
}
}
@Override
public boolean isDeviceInitializer(String packageName) {
if (!mHasFeature) {
return false;
}
synchronized (this) {
return mDeviceOwner != null
&& mDeviceOwner.hasDeviceInitializer()
&& mDeviceOwner.getDeviceInitializerPackageName().equals(packageName);
}
}
@Override
public String getDeviceInitializer() {
if (!mHasFeature) {
return null;
}
synchronized (this) {
if (mDeviceOwner != null && mDeviceOwner.hasDeviceInitializer()) {
return mDeviceOwner.getDeviceInitializerPackageName();
}
}
return null;
}
@Override
public void clearDeviceInitializer(String packageName) {
if (!mHasFeature) {
return;
}
if (packageName == null) {
throw new NullPointerException("packageName is null");
}
try {
int uid = mContext.getPackageManager().getPackageUid(packageName, 0);
if (uid != Binder.getCallingUid()) {
throw new SecurityException(
"clearDeviceInitializer can only be called by the device initializer");
}
} catch (NameNotFoundException e) {
throw new SecurityException(e);
}
if (!isDeviceInitializer(packageName)) {
throw new SecurityException(
"clearDeviceInitializer can only be called by the device initializer");
}
synchronized (this) {
long ident = Binder.clearCallingIdentity();
try {
if (mDeviceOwner != null) {
mDeviceOwner.clearDeviceInitializer();
mDeviceOwner.writeOwnerFile();
}
} finally {
Binder.restoreCallingIdentity(ident);
}
}
}
@Override
public boolean setProfileOwner(ComponentName who, String ownerName, int userHandle) {
if (!mHasFeature) {
@@ -3959,6 +4067,51 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return policy == null || policy.mUserSetupComplete;
}
@Override
public boolean setUserEnabled(ComponentName who) {
if (!mHasFeature) {
return false;
}
synchronized (this) {
if (who == null) {
throw new NullPointerException("ComponentName is null");
}
int userId = UserHandle.getCallingUserId();
ActiveAdmin activeAdmin =
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
if (!isDeviceInitializer(activeAdmin.info.getPackageName())) {
throw new SecurityException(
"This method can only be called by device initializers");
}
long id = Binder.clearCallingIdentity();
try {
if (!isDeviceOwner(activeAdmin.info.getPackageName())) {
IPackageManager ipm = AppGlobals.getPackageManager();
ipm.setComponentEnabledSetting(who,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP, userId);
removeActiveAdmin(who, userId);
}
if (userId == UserHandle.USER_OWNER) {
Settings.Global.putInt(mContext.getContentResolver(),
Settings.Global.DEVICE_PROVISIONED, 1);
}
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.USER_SETUP_COMPLETE, 1, userId);
} catch (RemoteException e) {
Log.i(LOG_TAG, "Can't talk to package manager", e);
return false;
} finally {
restoreCallingIdentity(id);
}
return true;
}
}
@Override
public void setProfileEnabled(ComponentName who) {
if (!mHasFeature) {