diff options
Diffstat (limited to 'android/app/admin/DevicePolicyManager.java')
-rw-r--r-- | android/app/admin/DevicePolicyManager.java | 628 |
1 files changed, 568 insertions, 60 deletions
diff --git a/android/app/admin/DevicePolicyManager.java b/android/app/admin/DevicePolicyManager.java index 0bca9690..7e80ac7b 100644 --- a/android/app/admin/DevicePolicyManager.java +++ b/android/app/admin/DevicePolicyManager.java @@ -16,7 +16,9 @@ package android.app.admin; +import android.annotation.CallbackExecutor; import android.annotation.ColorInt; +import android.annotation.Condemned; import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -49,6 +51,7 @@ import android.net.ProxyInfo; import android.net.Uri; import android.os.Bundle; import android.os.Handler; +import android.os.HandlerExecutor; import android.os.Parcelable; import android.os.PersistableBundle; import android.os.Process; @@ -57,7 +60,15 @@ import android.os.RemoteException; import android.os.UserHandle; import android.os.UserManager; import android.provider.ContactsContract.Directory; +import android.security.AttestedKeyPair; import android.security.Credentials; +import android.security.KeyChain; +import android.security.KeyChainException; +import android.security.keymaster.KeymasterCertificateChain; +import android.security.keystore.AttestationUtils; +import android.security.keystore.KeyAttestationException; +import android.security.keystore.KeyGenParameterSpec; +import android.security.keystore.ParcelableKeyGenParameterSpec; import android.service.restrictions.RestrictionsReceiver; import android.telephony.TelephonyManager; import android.util.ArraySet; @@ -75,6 +86,7 @@ import java.lang.annotation.RetentionPolicy; import java.net.InetSocketAddress; import java.net.Proxy; import java.security.KeyFactory; +import java.security.KeyPair; import java.security.NoSuchAlgorithmException; import java.security.PrivateKey; import java.security.cert.Certificate; @@ -88,6 +100,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.concurrent.Executor; /** * Public interface for managing policies enforced on a device. Most clients of this class must be @@ -1315,9 +1328,15 @@ public class DevicePolicyManager { public static final String DELEGATION_ENABLE_SYSTEM_APP = "delegation-enable-system-app"; /** + * Delegation for installing existing packages. This scope grants access to the + * {@link #installExistingPackage} API. + */ + public static final String DELEGATION_INSTALL_EXISTING_PACKAGE = + "delegation-install-existing-package"; + + /** * Delegation of management of uninstalled packages. This scope grants access to the * {@code #setKeepUninstalledPackages} and {@code #getKeepUninstalledPackages} APIs. - * @hide */ public static final String DELEGATION_KEEP_UNINSTALLED_PACKAGES = "delegation-keep-uninstalled-packages"; @@ -1360,8 +1379,13 @@ public class DevicePolicyManager { /** * @hide */ - @IntDef({STATE_USER_UNMANAGED, STATE_USER_SETUP_INCOMPLETE, STATE_USER_SETUP_COMPLETE, - STATE_USER_SETUP_FINALIZED, STATE_USER_PROFILE_COMPLETE}) + @IntDef(prefix = { "STATE_USER_" }, value = { + STATE_USER_UNMANAGED, + STATE_USER_SETUP_INCOMPLETE, + STATE_USER_SETUP_COMPLETE, + STATE_USER_SETUP_FINALIZED, + STATE_USER_PROFILE_COMPLETE + }) @Retention(RetentionPolicy.SOURCE) public @interface UserProvisioningState {} @@ -1534,11 +1558,13 @@ public class DevicePolicyManager { * @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef({CODE_OK, CODE_HAS_DEVICE_OWNER, CODE_USER_HAS_PROFILE_OWNER, CODE_USER_NOT_RUNNING, + @IntDef(prefix = { "CODE_" }, value = { + CODE_OK, CODE_HAS_DEVICE_OWNER, CODE_USER_HAS_PROFILE_OWNER, CODE_USER_NOT_RUNNING, CODE_USER_SETUP_COMPLETED, CODE_NOT_SYSTEM_USER, CODE_HAS_PAIRED, CODE_MANAGED_USERS_NOT_SUPPORTED, CODE_SYSTEM_USER, CODE_CANNOT_ADD_MANAGED_PROFILE, CODE_NOT_SYSTEM_USER_SPLIT, CODE_DEVICE_ADMIN_NOT_SUPPORTED, - CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER, CODE_ADD_MANAGED_PROFILE_DISALLOWED}) + CODE_SPLIT_SYSTEM_USER_DEVICE_SYSTEM_USER, CODE_ADD_MANAGED_PROFILE_DISALLOWED + }) public @interface ProvisioningPreCondition {} /** @@ -1620,11 +1646,15 @@ public class DevicePolicyManager { * @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(flag = true, - value = {LOCK_TASK_FEATURE_NONE, LOCK_TASK_FEATURE_SYSTEM_INFO, - LOCK_TASK_FEATURE_NOTIFICATIONS, LOCK_TASK_FEATURE_HOME, - LOCK_TASK_FEATURE_RECENTS, LOCK_TASK_FEATURE_GLOBAL_ACTIONS, - LOCK_TASK_FEATURE_KEYGUARD}) + @IntDef(flag = true, prefix = { "LOCK_TASK_FEATURE_" }, value = { + LOCK_TASK_FEATURE_NONE, + LOCK_TASK_FEATURE_SYSTEM_INFO, + LOCK_TASK_FEATURE_NOTIFICATIONS, + LOCK_TASK_FEATURE_HOME, + LOCK_TASK_FEATURE_RECENTS, + LOCK_TASK_FEATURE_GLOBAL_ACTIONS, + LOCK_TASK_FEATURE_KEYGUARD + }) public @interface LockTaskFeature {} /** @@ -2605,10 +2635,115 @@ public class DevicePolicyManager { } /** + * The maximum number of characters allowed in the password blacklist. + */ + private static final int PASSWORD_BLACKLIST_CHARACTER_LIMIT = 128 * 1000; + + /** + * Throws an exception if the password blacklist is too large. + * + * @hide + */ + public static void enforcePasswordBlacklistSize(List<String> blacklist) { + if (blacklist == null) { + return; + } + long characterCount = 0; + for (final String item : blacklist) { + characterCount += item.length(); + } + if (characterCount > PASSWORD_BLACKLIST_CHARACTER_LIMIT) { + throw new IllegalArgumentException("128 thousand blacklist character limit exceeded by " + + (characterCount - PASSWORD_BLACKLIST_CHARACTER_LIMIT) + " characters"); + } + } + + /** + * Called by an application that is administering the device to blacklist passwords. + * <p> + * Any blacklisted password or PIN is prevented from being enrolled by the user or the admin. + * Note that the match against the blacklist is case insensitive. The blacklist applies for all + * password qualities requested by {@link #setPasswordQuality} however it is not taken into + * consideration by {@link #isActivePasswordSufficient}. + * <p> + * The blacklist can be cleared by passing {@code null} or an empty list. The blacklist is + * given a name that is used to track which blacklist is currently set by calling {@link + * #getPasswordBlacklistName}. If the blacklist is being cleared, the name is ignored and {@link + * #getPasswordBlacklistName} will return {@code null}. The name can only be {@code null} when + * the blacklist is being cleared. + * <p> + * The blacklist is limited to a total of 128 thousand characters rather than limiting to a + * number of entries. + * <p> + * This method can be called on the {@link DevicePolicyManager} instance returned by + * {@link #getParentProfileInstance(ComponentName)} in order to set restrictions on the parent + * profile. + * + * @param admin the {@link DeviceAdminReceiver} this request is associated with + * @param name name to associate with the blacklist + * @param blacklist list of passwords to blacklist or {@code null} to clear the blacklist + * @return whether the new blacklist was successfully installed + * @throws SecurityException if {@code admin} is not a device or profile owner + * @throws IllegalArgumentException if the blacklist surpasses the character limit + * @throws NullPointerException if {@code name} is {@code null} when setting a non-empty list + * + * @see #getPasswordBlacklistName + * @see #isActivePasswordSufficient + * @see #resetPasswordWithToken + */ + public boolean setPasswordBlacklist(@NonNull ComponentName admin, @Nullable String name, + @Nullable List<String> blacklist) { + enforcePasswordBlacklistSize(blacklist); + + try { + return mService.setPasswordBlacklist(admin, name, blacklist, mParentInstance); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Get the name of the password blacklist set by the given admin. + * + * @param admin the {@link DeviceAdminReceiver} this request is associated with + * @return the name of the blacklist or {@code null} if no blacklist is set + * + * @see #setPasswordBlacklist + */ + public @Nullable String getPasswordBlacklistName(@NonNull ComponentName admin) { + try { + return mService.getPasswordBlacklistName(admin, myUserId(), mParentInstance); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Test if a given password is blacklisted. + * + * @param userId the user to valiate for + * @param password the password to check against the blacklist + * @return whether the password is blacklisted + * + * @see #setPasswordBlacklist + * + * @hide + */ + @RequiresPermission(android.Manifest.permission.TEST_BLACKLISTED_PASSWORD) + public boolean isPasswordBlacklisted(@UserIdInt int userId, @NonNull String password) { + try { + return mService.isPasswordBlacklisted(userId, password); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** * Determine whether the current password the user has set is sufficient to meet the policy * requirements (e.g. quality, minimum length) that have been requested by the admins of this * user and its participating profiles. Restrictions on profiles that have a separate challenge - * are not taken into account. The user must be unlocked in order to perform the check. + * are not taken into account. The user must be unlocked in order to perform the check. The + * password blacklist is not considered when checking sufficiency. * <p> * The calling device admin must have requested * {@link DeviceAdminInfo#USES_POLICY_LIMIT_PASSWORD} to be able to call this method; if it has @@ -2635,6 +2770,29 @@ public class DevicePolicyManager { } /** + * When called by a profile owner of a managed profile returns true if the profile uses unified + * challenge with its parent user. + * + * <strong>Note: This method is not concerned with password quality and will return false if + * the profile has empty password as a separate challenge. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @throws SecurityException if {@code admin} is not a profile owner of a managed profile. + * @see UserManager#DISALLOW_UNIFIED_PASSWORD + */ + public boolean isUsingUnifiedPassword(@NonNull ComponentName admin) { + throwIfParentInstance("isUsingUnifiedPassword"); + if (mService != null) { + try { + return mService.isUsingUnifiedPassword(admin); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return true; + } + + /** * Determine whether the current profile password the user has set is sufficient * to meet the policy requirements (e.g. quality, minimum length) that have been * requested by the admins of the parent user and its profiles. @@ -3049,23 +3207,6 @@ public class DevicePolicyManager { } /** - * Returns maximum time to lock that applied by all profiles in this user. We do this because we - * do not have a separate timeout to lock for work challenge only. - * - * @hide - */ - public long getMaximumTimeToLockForUserAndProfiles(int userHandle) { - if (mService != null) { - try { - return mService.getMaximumTimeToLockForUserAndProfiles(userHandle); - } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); - } - } - return 0; - } - - /** * Called by a device/profile owner to set the timeout after which unlocking with secondary, non * strong auth (e.g. fingerprint, trust agents) times out, i.e. the user has to use a strong * authentication method like password, pin or pattern. @@ -3153,7 +3294,9 @@ public class DevicePolicyManager { /** @hide */ @Retention(RetentionPolicy.SOURCE) - @IntDef(flag=true, value={FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY}) + @IntDef(flag = true, prefix = { "FLAG_EVICT_" }, value = { + FLAG_EVICT_CREDENTIAL_ENCRYPTION_KEY + }) public @interface LockNowFlag {} /** @@ -3468,6 +3611,16 @@ public class DevicePolicyManager { @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION) public static final String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION"; + + /** + * Broadcast action: notify managed provisioning that new managed user is created. + * + * @hide + */ + @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_MANAGED_USER_CREATED = + "android.app.action.MANAGED_USER_CREATED"; + /** * Widgets are enabled in keyguard */ @@ -3943,6 +4096,108 @@ public class DevicePolicyManager { } /** + * Called by a device or profile owner, or delegated certificate installer, to generate a + * new private/public key pair. If the device supports key generation via secure hardware, + * this method is useful for creating a key in KeyChain that never left the secure hardware. + * + * Access to the key is controlled the same way as in {@link #installKeyPair}. + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. + * @param algorithm The key generation algorithm, see {@link java.security.KeyPairGenerator}. + * @param keySpec Specification of the key to generate, see + * {@link java.security.KeyPairGenerator}. + * @return A non-null {@code AttestedKeyPair} if the key generation succeeded, null otherwise. + * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile + * owner. + * @throws IllegalArgumentException if the alias in {@code keySpec} is empty, or if the + * algorithm specification in {@code keySpec} is not {@code RSAKeyGenParameterSpec} + * or {@code ECGenParameterSpec}. + */ + public AttestedKeyPair generateKeyPair(@Nullable ComponentName admin, + @NonNull String algorithm, @NonNull KeyGenParameterSpec keySpec) { + throwIfParentInstance("generateKeyPair"); + try { + final ParcelableKeyGenParameterSpec parcelableSpec = + new ParcelableKeyGenParameterSpec(keySpec); + KeymasterCertificateChain attestationChain = new KeymasterCertificateChain(); + final boolean success = mService.generateKeyPair( + admin, mContext.getPackageName(), algorithm, parcelableSpec, attestationChain); + if (!success) { + Log.e(TAG, "Error generating key via DevicePolicyManagerService."); + return null; + } + + final String alias = keySpec.getKeystoreAlias(); + final KeyPair keyPair = KeyChain.getKeyPair(mContext, alias); + Certificate[] outputChain = null; + try { + if (AttestationUtils.isChainValid(attestationChain)) { + outputChain = AttestationUtils.parseCertificateChain(attestationChain); + } + } catch (KeyAttestationException e) { + Log.e(TAG, "Error parsing attestation chain for alias " + alias, e); + mService.removeKeyPair(admin, mContext.getPackageName(), alias); + return null; + } + return new AttestedKeyPair(keyPair, outputChain); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (KeyChainException e) { + Log.w(TAG, "Failed to generate key", e); + } catch (InterruptedException e) { + Log.w(TAG, "Interrupted while generating key", e); + Thread.currentThread().interrupt(); + } + return null; + } + + + /** + * Called by a device or profile owner, or delegated certificate installer, to associate + * certificates with a key pair that was generated using {@link #generateKeyPair}, and + * set whether the key is available for the user to choose in the certificate selection + * prompt. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with, or + * {@code null} if calling from a delegated certificate installer. + * @param alias The private key alias under which to install the certificate. The {@code alias} + * should denote an existing private key. If a certificate with that alias already + * exists, it will be overwritten. + * @param certs The certificate chain to install. The chain should start with the leaf + * certificate and include the chain of trust in order. This will be returned by + * {@link android.security.KeyChain#getCertificateChain}. + * @param isUserSelectable {@code true} to indicate that a user can select this key via the + * certificate selection prompt, {@code false} to indicate that this key can only be + * granted access by implementing + * {@link android.app.admin.DeviceAdminReceiver#onChoosePrivateKeyAlias}. + * @return {@code true} if the provided {@code alias} exists and the certificates has been + * successfully associated with it, {@code false} otherwise. + * @throws SecurityException if {@code admin} is not {@code null} and not a device or profile + * owner, or {@code admin} is null but the calling application is not a delegated + * certificate installer. + */ + public boolean setKeyPairCertificate(@Nullable ComponentName admin, + @NonNull String alias, @NonNull List<Certificate> certs, boolean isUserSelectable) { + throwIfParentInstance("setKeyPairCertificate"); + try { + final byte[] pemCert = Credentials.convertToPem(certs.get(0)); + byte[] pemChain = null; + if (certs.size() > 1) { + pemChain = Credentials.convertToPem( + certs.subList(1, certs.size()).toArray(new Certificate[0])); + } + return mService.setKeyPairCertificate(admin, mContext.getPackageName(), alias, pemCert, + pemChain, isUserSelectable); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } catch (CertificateException | IOException e) { + Log.w(TAG, "Could not pem-encode certificate", e); + } + return false; + } + + + /** * @return the alias of a given CA certificate in the certificate store, or {@code null} if it * doesn't exist. */ @@ -4212,16 +4467,16 @@ public class DevicePolicyManager { /** * Called by a device owner to request a bugreport. * <p> - * If the device contains secondary users or profiles, they must be affiliated with the device - * owner user. Otherwise a {@link SecurityException} will be thrown. See - * {@link #setAffiliationIds}. + * If the device contains secondary users or profiles, they must be affiliated with the device. + * Otherwise a {@link SecurityException} will be thrown. See {@link #isAffiliatedUser}. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @return {@code true} if the bugreport collection started successfully, or {@code false} if it * wasn't triggered because a previous bugreport operation is still active (either the * bugreport is still running or waiting for the user to share or decline) * @throws SecurityException if {@code admin} is not a device owner, or there is at least one - * profile or secondary user that is not affiliated with the device owner user. + * profile or secondary user that is not affiliated with the device. + * @see #isAffiliatedUser */ public boolean requestBugreport(@NonNull ComponentName admin) { throwIfParentInstance("requestBugreport"); @@ -6035,7 +6290,6 @@ public class DevicePolicyManager { * @return List of package names to keep cached. * @see #setDelegatedScopes * @see #DELEGATION_KEEP_UNINSTALLED_PACKAGES - * @hide */ public @Nullable List<String> getKeepUninstalledPackages(@Nullable ComponentName admin) { throwIfParentInstance("getKeepUninstalledPackages"); @@ -6063,7 +6317,6 @@ public class DevicePolicyManager { * @throws SecurityException if {@code admin} is not a device owner. * @see #setDelegatedScopes * @see #DELEGATION_KEEP_UNINSTALLED_PACKAGES - * @hide */ public void setKeepUninstalledPackages(@Nullable ComponentName admin, @NonNull List<String> packageNames) { @@ -6151,21 +6404,27 @@ public class DevicePolicyManager { public static final int MAKE_USER_DEMO = 0x0004; /** - * Flag used by {@link #createAndManageUser} to specificy that the newly created user should be + * Flag used by {@link #createAndManageUser} to specify that the newly created user should be * started in the background as part of the user creation. */ - // TODO: Investigate solutions for the case where reboot happens before setup is completed. public static final int START_USER_IN_BACKGROUND = 0x0008; /** + * Flag used by {@link #createAndManageUser} to specify that the newly created user should skip + * the disabling of system apps during provisioning. + */ + public static final int LEAVE_ALL_SYSTEM_APPS_ENABLED = 0x0010; + + /** * @hide */ - @IntDef( - flag = true, - prefix = {"SKIP_", "MAKE_USER_", "START_"}, - value = {SKIP_SETUP_WIZARD, MAKE_USER_EPHEMERAL, MAKE_USER_DEMO, - START_USER_IN_BACKGROUND} - ) + @IntDef(flag = true, prefix = { "SKIP_", "MAKE_USER_", "START_", "LEAVE_" }, value = { + SKIP_SETUP_WIZARD, + MAKE_USER_EPHEMERAL, + MAKE_USER_DEMO, + START_USER_IN_BACKGROUND, + LEAVE_ALL_SYSTEM_APPS_ENABLED + }) @Retention(RetentionPolicy.SOURCE) public @interface CreateAndManageUserFlags {} @@ -6219,7 +6478,7 @@ public class DevicePolicyManager { * @return {@code true} if the user was removed, {@code false} otherwise. * @throws SecurityException if {@code admin} is not a device owner. */ - public boolean removeUser(@NonNull ComponentName admin, UserHandle userHandle) { + public boolean removeUser(@NonNull ComponentName admin, @NonNull UserHandle userHandle) { throwIfParentInstance("removeUser"); try { return mService.removeUser(admin, userHandle); @@ -6230,6 +6489,7 @@ public class DevicePolicyManager { /** * Called by a device owner to switch the specified user to the foreground. + * <p> This cannot be used to switch to a managed profile. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param userHandle the user to switch to; null will switch to primary. @@ -6247,6 +6507,80 @@ public class DevicePolicyManager { } /** + * Called by a device owner to stop the specified secondary user. + * <p> This cannot be used to stop the primary user or a managed profile. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param userHandle the user to be stopped. + * @return {@code true} if the user can be stopped, {@code false} otherwise. + * @throws SecurityException if {@code admin} is not a device owner. + */ + public boolean stopUser(@NonNull ComponentName admin, @NonNull UserHandle userHandle) { + throwIfParentInstance("stopUser"); + try { + return mService.stopUser(admin, userHandle); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Called by a profile owner that is affiliated with the device to stop the calling user + * and switch back to primary. + * <p> This has no effect when called on a managed profile. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @return {@code true} if the exit was successful, {@code false} otherwise. + * @throws SecurityException if {@code admin} is not a profile owner affiliated with the device. + * @see #isAffiliatedUser + */ + public boolean logoutUser(@NonNull ComponentName admin) { + throwIfParentInstance("logoutUser"); + try { + return mService.logoutUser(admin); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Called by a device owner to list all secondary users on the device, excluding managed + * profiles. + * <p> Used for various user management APIs, including {@link #switchUser}, {@link #removeUser} + * and {@link #stopUser}. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @return list of other {@link UserHandle}s on the device. + * @throws SecurityException if {@code admin} is not a device owner. + * @see #switchUser + * @see #removeUser + * @see #stopUser + */ + public List<UserHandle> getSecondaryUsers(@NonNull ComponentName admin) { + throwIfParentInstance("getSecondaryUsers"); + try { + return mService.getSecondaryUsers(admin); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Checks if the profile owner is running in an ephemeral user. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @return whether the profile owner is running in an ephemeral user. + */ + public boolean isEphemeralUser(@NonNull ComponentName admin) { + throwIfParentInstance("isEphemeralUser"); + try { + return mService.isEphemeralUser(admin); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** * Retrieves the application restrictions for a given target application running in the calling * user. * <p> @@ -6481,6 +6815,37 @@ public class DevicePolicyManager { } /** + * Install an existing package that has been installed in another user, or has been kept after + * removal via {@link #setKeepUninstalledPackages}. + * This function can be called by a device owner, profile owner or a delegate given + * the {@link #DELEGATION_INSTALL_EXISTING_PACKAGE} scope via {@link #setDelegatedScopes}. + * When called in a secondary user or managed profile, the user/profile must be affiliated with + * the device. See {@link #isAffiliatedUser}. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param packageName The package to be installed in the calling profile. + * @return {@code true} if the app is installed; {@code false} otherwise. + * @throws SecurityException if {@code admin} is not the device owner, or the profile owner of + * an affiliated user or profile. + * @see #setKeepUninstalledPackages + * @see #setDelegatedScopes + * @see #isAffiliatedUser + * @see #DELEGATION_PACKAGE_ACCESS + */ + public boolean installExistingPackage(@NonNull ComponentName admin, String packageName) { + throwIfParentInstance("installExistingPackage"); + if (mService != null) { + try { + return mService.installExistingPackage(admin, mContext.getPackageName(), + packageName); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + return false; + } + + /** * Called by a device owner or profile owner to disable account management for a specific type * of account. * <p> @@ -6551,13 +6916,14 @@ public class DevicePolicyManager { * package list results in locked tasks belonging to those packages to be finished. * <p> * This function can only be called by the device owner or by a profile owner of a user/profile - * that is affiliated with the device owner user. See {@link #setAffiliationIds}. Any packages + * that is affiliated with the device. See {@link #isAffiliatedUser}. Any packages * set via this method will be cleared if the user becomes unaffiliated. * * @param packages The list of packages allowed to enter lock task mode * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @throws SecurityException if {@code admin} is not the device owner, or the profile owner of * an affiliated user or profile. + * @see #isAffiliatedUser * @see Activity#startLockTask() * @see DeviceAdminReceiver#onLockTaskModeEntering(Context, Intent, String) * @see DeviceAdminReceiver#onLockTaskModeExiting(Context, Intent) @@ -6580,6 +6946,7 @@ public class DevicePolicyManager { * * @throws SecurityException if {@code admin} is not the device owner, or the profile owner of * an affiliated user or profile. + * @see #isAffiliatedUser * @see #setLockTaskPackages */ public @NonNull String[] getLockTaskPackages(@NonNull ComponentName admin) { @@ -6619,7 +6986,7 @@ public class DevicePolicyManager { * enabled. * <p> * This function can only be called by the device owner or by a profile owner of a user/profile - * that is affiliated with the device owner user. See {@link #setAffiliationIds}. Any features + * that is affiliated with the device. See {@link #isAffiliatedUser}. Any features * set via this method will be cleared if the user becomes unaffiliated. * * @param admin Which {@link DeviceAdminReceiver} this request is associated with. @@ -6633,6 +7000,7 @@ public class DevicePolicyManager { * {@link #LOCK_TASK_FEATURE_KEYGUARD} * @throws SecurityException if {@code admin} is not the device owner, or the profile owner of * an affiliated user or profile. + * @see #isAffiliatedUser */ public void setLockTaskFeatures(@NonNull ComponentName admin, @LockTaskFeature int flags) { throwIfParentInstance("setLockTaskFeatures"); @@ -6652,7 +7020,8 @@ public class DevicePolicyManager { * @return bitfield of flags. See {@link #setLockTaskFeatures(ComponentName, int)} for a list. * @throws SecurityException if {@code admin} is not the device owner, or the profile owner of * an affiliated user or profile. - * @see #setLockTaskFeatures(ComponentName, int) + * @see #isAffiliatedUser + * @see #setLockTaskFeatures */ public @LockTaskFeature int getLockTaskFeatures(@NonNull ComponentName admin) { throwIfParentInstance("getLockTaskFeatures"); @@ -6667,7 +7036,7 @@ public class DevicePolicyManager { } /** - * Called by device owners to update {@link android.provider.Settings.Global} settings. + * Called by device owner to update {@link android.provider.Settings.Global} settings. * Validation that the value of the setting is in the correct form for the setting type should * be performed by the caller. * <p> @@ -6716,6 +7085,37 @@ public class DevicePolicyManager { } /** + * Called by device owner to update {@link android.provider.Settings.System} settings. + * Validation that the value of the setting is in the correct form for the setting type should + * be performed by the caller. + * <p> + * The settings that can be updated with this method are: + * <ul> + * <li>{@link android.provider.Settings.System#SCREEN_BRIGHTNESS}</li> + * <li>{@link android.provider.Settings.System#SCREEN_BRIGHTNESS_MODE}</li> + * <li>{@link android.provider.Settings.System#SCREEN_OFF_TIMEOUT}</li> + * </ul> + * <p> + * + * @see android.provider.Settings.System#SCREEN_OFF_TIMEOUT + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param setting The name of the setting to update. + * @param value The value to update the setting to. + * @throws SecurityException if {@code admin} is not a device owner. + */ + public void setSystemSetting(@NonNull ComponentName admin, @NonNull String setting, + String value) { + throwIfParentInstance("setSystemSetting"); + if (mService != null) { + try { + mService.setSystemSetting(admin, setting, value); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + } + + /** * Called by device owner to set the system wall clock time. This only takes effect if called * when {@link android.provider.Settings.Global#AUTO_TIME} is 0, otherwise {@code false} will be * returned. @@ -7619,6 +8019,7 @@ public class DevicePolicyManager { * @param admin Which device owner this request is associated with. * @param enabled whether security logging should be enabled or not. * @throws SecurityException if {@code admin} is not a device owner. + * @see #setAffiliationIds * @see #retrieveSecurityLogs */ public void setSecurityLoggingEnabled(@NonNull ComponentName admin, boolean enabled) { @@ -7657,14 +8058,14 @@ public class DevicePolicyManager { * owner has been notified via {@link DeviceAdminReceiver#onSecurityLogsAvailable}. * * <p>If there is any other user or profile on the device, it must be affiliated with the - * device owner. Otherwise a {@link SecurityException} will be thrown. See - * {@link #setAffiliationIds} + * device. Otherwise a {@link SecurityException} will be thrown. See {@link #isAffiliatedUser}. * * @param admin Which device owner this request is associated with. * @return the new batch of security logs which is a list of {@link SecurityEvent}, * or {@code null} if rate limitation is exceeded or if logging is currently disabled. * @throws SecurityException if {@code admin} is not a device owner, or there is at least one - * profile or secondary user that is not affiliated with the device owner user. + * profile or secondary user that is not affiliated with the device. + * @see #isAffiliatedUser * @see DeviceAdminReceiver#onSecurityLogsAvailable */ public @Nullable List<SecurityEvent> retrieveSecurityLogs(@NonNull ComponentName admin) { @@ -7707,14 +8108,14 @@ public class DevicePolicyManager { * about data corruption when parsing. </strong> * * <p>If there is any other user or profile on the device, it must be affiliated with the - * device owner. Otherwise a {@link SecurityException} will be thrown. See - * {@link #setAffiliationIds} + * device. Otherwise a {@link SecurityException} will be thrown. See {@link #isAffiliatedUser}. * * @param admin Which device owner this request is associated with. * @return Device logs from before the latest reboot of the system, or {@code null} if this API * is not supported on the device. * @throws SecurityException if {@code admin} is not a device owner, or there is at least one - * profile or secondary user that is not affiliated with the device owner user. + * profile or secondary user that is not affiliated with the device. + * @see #isAffiliatedUser * @see #retrieveSecurityLogs */ public @Nullable List<SecurityEvent> retrievePreRebootSecurityLogs( @@ -7922,6 +8323,9 @@ public class DevicePolicyManager { * Indicates the entity that controls the device or profile owner. Two users/profiles are * affiliated if the set of ids set by their device or profile owners intersect. * + * <p>A user/profile that is affiliated with the device owner user is considered to be + * affiliated with the device. + * * <p><strong>Note:</strong> Features that depend on user affiliation (such as security logging * or {@link #bindDeviceAdminServiceAsUser}) won't be available when a secondary user or profile * is created, until it becomes affiliated. Therefore it is recommended that the appropriate @@ -7932,6 +8336,7 @@ public class DevicePolicyManager { * @param ids A set of opaque non-empty affiliation ids. * * @throws IllegalArgumentException if {@code ids} is null or contains an empty string. + * @see #isAffiliatedUser */ public void setAffiliationIds(@NonNull ComponentName admin, @NonNull Set<String> ids) { throwIfParentInstance("setAffiliationIds"); @@ -7959,13 +8364,12 @@ public class DevicePolicyManager { } /** - * @hide * Returns whether this user/profile is affiliated with the device. * <p> * By definition, the user that the device owner runs on is always affiliated with the device. * Any other user/profile is considered affiliated with the device if the set specified by its * profile owner via {@link #setAffiliationIds} intersects with the device owner's. - * + * @see #setAffiliationIds */ public boolean isAffiliatedUser() { throwIfParentInstance("isAffiliatedUser"); @@ -8178,6 +8582,7 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param enabled whether network logging should be enabled or not. * @throws SecurityException if {@code admin} is not a device owner. + * @see #setAffiliationIds * @see #retrieveNetworkLogs */ public void setNetworkLoggingEnabled(@NonNull ComponentName admin, boolean enabled) { @@ -8233,7 +8638,8 @@ public class DevicePolicyManager { * {@code null} if the batch represented by batchToken is no longer available or if * logging is disabled. * @throws SecurityException if {@code admin} is not a device owner, or there is at least one - * profile or secondary user that is not affiliated with the device owner user. + * profile or secondary user that is not affiliated with the device. + * @see #setAffiliationIds * @see DeviceAdminReceiver#onNetworkLogsAvailable */ public @Nullable List<NetworkEvent> retrieveNetworkLogs(@NonNull ComponentName admin, @@ -8411,6 +8817,15 @@ public class DevicePolicyManager { } } + /** {@hide} */ + @Condemned + @Deprecated + public boolean clearApplicationUserData(@NonNull ComponentName admin, + @NonNull String packageName, @NonNull OnClearApplicationUserDataListener listener, + @NonNull Handler handler) { + return clearApplicationUserData(admin, packageName, listener, new HandlerExecutor(handler)); + } + /** * Called by the device owner or profile owner to clear application user data of a given * package. The behaviour of this is equivalent to the target application calling @@ -8422,19 +8837,20 @@ public class DevicePolicyManager { * @param admin Which {@link DeviceAdminReceiver} this request is associated with. * @param packageName The name of the package which will have its user data wiped. * @param listener A callback object that will inform the caller when the clearing is done. - * @param handler The handler indicating the thread on which the listener should be invoked. + * @param executor The executor through which the listener should be invoked. * @throws SecurityException if the caller is not the device owner/profile owner. * @return whether the clearing succeeded. */ public boolean clearApplicationUserData(@NonNull ComponentName admin, @NonNull String packageName, @NonNull OnClearApplicationUserDataListener listener, - @NonNull Handler handler) { + @NonNull @CallbackExecutor Executor executor) { throwIfParentInstance("clearAppData"); + Preconditions.checkNotNull(executor); try { return mService.clearApplicationUserData(admin, packageName, new IPackageDataObserver.Stub() { public void onRemoveCompleted(String pkg, boolean succeeded) { - handler.post(() -> + executor.execute(() -> listener.onApplicationUserDataCleared(pkg, succeeded)); } }); @@ -8444,6 +8860,37 @@ public class DevicePolicyManager { } /** + * Called by a device owner to specify whether logout is enabled for all secondary users. The + * system may show a logout button that stops the user and switches back to the primary user. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param enabled whether logout should be enabled or not. + * @throws SecurityException if {@code admin} is not a device owner. + */ + public void setLogoutEnabled(@NonNull ComponentName admin, boolean enabled) { + throwIfParentInstance("setLogoutEnabled"); + try { + mService.setLogoutEnabled(admin, enabled); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** + * Returns whether logout is enabled by a device owner. + * + * @return {@code true} if logout is enabled by device owner, {@code false} otherwise. + */ + public boolean isLogoutEnabled() { + throwIfParentInstance("isLogoutEnabled"); + try { + return mService.isLogoutEnabled(); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + /** * Callback used in {@link #clearApplicationUserData} * to indicate that the clearing of an application's user data is done. */ @@ -8457,4 +8904,65 @@ public class DevicePolicyManager { */ void onApplicationUserDataCleared(String packageName, boolean succeeded); } + + /** + * Returns set of system apps that should be removed during provisioning. + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param userId ID of the user to be provisioned. + * @param provisioningAction action indicating type of provisioning, should be one of + * {@link #ACTION_PROVISION_MANAGED_DEVICE}, {@link #ACTION_PROVISION_MANAGED_PROFILE} or + * {@link #ACTION_PROVISION_MANAGED_USER}. + * + * @hide + */ + public Set<String> getDisallowedSystemApps(ComponentName admin, int userId, + String provisioningAction) { + try { + return new ArraySet<>( + mService.getDisallowedSystemApps(admin, userId, provisioningAction)); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + + //TODO STOPSHIP Add link to onTransferComplete callback when implemented. + /** + * Transfers the current administrator. All policies from the current administrator are + * migrated to the new administrator. The whole operation is atomic - the transfer is either + * complete or not done at all. + * + * Depending on the current administrator (device owner, profile owner, corporate owned + * profile owner), you have the following expected behaviour: + * <ul> + * <li>A device owner can only be transferred to a new device owner</li> + * <li>A profile owner can only be transferred to a new profile owner</li> + * <li>A corporate owned managed profile can have two cases: + * <ul> + * <li>If the device owner and profile owner are the same package, + * both will be transferred.</li> + * <li>If the device owner and profile owner are different packages, + * and if this method is called from the profile owner, only the profile owner + * is transferred. Similarly, if it is called from the device owner, only + * the device owner is transferred.</li> + * </ul> + * </li> + * </ul> + * + * @param admin Which {@link DeviceAdminReceiver} this request is associated with. + * @param target Which {@link DeviceAdminReceiver} we want the new administrator to be. + * @param bundle Parameters - This bundle allows the current administrator to pass data to the + * new administrator. The parameters will be received in the + * onTransferComplete callback. + * @hide + */ + public void transferOwner(@NonNull ComponentName admin, @NonNull ComponentName target, + PersistableBundle bundle) { + throwIfParentInstance("transferOwner"); + try { + mService.transferOwner(admin, target, bundle); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } } |