diff options
Diffstat (limited to 'services/devicepolicy')
-rw-r--r-- | services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java | 90 | ||||
-rw-r--r-- | services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java | 682 |
2 files changed, 462 insertions, 310 deletions
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java index 9fd0e09..ea59d4b 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java @@ -39,18 +39,21 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.io.PrintWriter; import java.util.HashMap; +import java.util.Map; import java.util.Set; /** * Stores and restores state for the Device and Profile owners. By definition there can be * only one device owner, but there may be a profile owner for each user. */ -public class DeviceOwner { +class DeviceOwner { private static final String TAG = "DevicePolicyManagerService"; 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"; @@ -66,6 +69,9 @@ public 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>(); @@ -102,12 +108,11 @@ public class DeviceOwner { } /** - * @deprecated Use a component name instead of package name - * Creates an instance of the device owner object with the profile owner set. + * Creates an instance of the device owner object with the device initializer set. */ - static DeviceOwner createWithProfileOwner(String packageName, String ownerName, int userId) { + static DeviceOwner createWithDeviceInitializer(String packageName, String ownerName) { DeviceOwner owner = new DeviceOwner(); - owner.mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName)); + owner.mDeviceInitializer = new OwnerInfo(ownerName, packageName); return owner; } @@ -136,11 +141,24 @@ public class DeviceOwner { mDeviceOwner = null; } - /** - * @deprecated - */ - void setProfileOwner(String packageName, String ownerName, int userId) { - mProfileOwners.put(userId, new OwnerInfo(ownerName, packageName)); + 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) { @@ -151,16 +169,6 @@ public class DeviceOwner { mProfileOwners.remove(userId); } - /** - * @deprecated Use getProfileOwnerComponent - * @param userId - * @return - */ - String getProfileOwnerPackageName(int userId) { - OwnerInfo profileOwner = mProfileOwners.get(userId); - return profileOwner != null ? profileOwner.packageName : null; - } - ComponentName getProfileOwnerComponent(int userId) { OwnerInfo profileOwner = mProfileOwners.get(userId); return profileOwner != null ? profileOwner.admin : null; @@ -207,6 +215,7 @@ public class DeviceOwner { return false; } + @VisibleForTesting void readOwnerFile() { try { InputStream input = openRead(); @@ -223,6 +232,10 @@ public 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 +272,7 @@ public class DeviceOwner { } } + @VisibleForTesting void writeOwnerFile() { synchronized (this) { writeOwnerFileLocked(); @@ -282,6 +296,16 @@ public 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()) { @@ -329,10 +353,10 @@ public class DeviceOwner { } } - static class OwnerInfo { - public String name; - public String packageName; - public ComponentName admin; + private static class OwnerInfo { + public final String name; + public final String packageName; + public final ComponentName admin; public OwnerInfo(String name, String packageName) { this.name = name; @@ -345,5 +369,23 @@ public class DeviceOwner { this.admin = admin; this.packageName = admin.getPackageName(); } + public void dump(String prefix, PrintWriter pw) { + pw.println(prefix + "admin=" + admin); + pw.println(prefix + "name=" + name); + pw.println(); + } + } + + public void dump(String prefix, PrintWriter pw) { + if (mDeviceOwner != null) { + pw.println(prefix + "Device Owner: "); + mDeviceOwner.dump(prefix + " ", pw); + } + if (mProfileOwners != null) { + for (Map.Entry<Integer, OwnerInfo> entry : mProfileOwners.entrySet()) { + pw.println(prefix + "Profile Owner (User " + entry.getKey() + "): "); + entry.getValue().dump(prefix + " ", pw); + } + } } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 40e2056..00d7971 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -48,8 +48,10 @@ import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; +import android.content.pm.ServiceInfo; import android.content.pm.UserInfo; import android.database.ContentObserver; +import android.graphics.Bitmap; import android.hardware.usb.UsbManager; import android.media.AudioManager; import android.media.IAudioService; @@ -77,6 +79,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.provider.Settings; import android.security.Credentials; +import android.security.IKeyChainAliasCallback; import android.security.IKeyChainService; import android.security.KeyChain; import android.security.KeyChain.KeyChainConnection; @@ -98,6 +101,7 @@ import com.android.internal.R; import com.android.internal.os.storage.ExternalStorageFormatter; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; +import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.internal.widget.LockPatternUtils; import com.android.server.LocalServices; @@ -176,6 +180,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DEVICE_OWNER_USER_RESTRICTIONS.add(UserManager.DISALLOW_SMS); } + // The following user restrictions cannot be changed by any active admin, including device + // owner and profile owner. + private static final Set<String> IMMUTABLE_USER_RESTRICTIONS; + static { + IMMUTABLE_USER_RESTRICTIONS = new HashSet(); + IMMUTABLE_USER_RESTRICTIONS.add(UserManager.DISALLOW_WALLPAPER); + } + private static final Set<String> SECURE_SETTINGS_WHITELIST; private static final Set<String> SECURE_SETTINGS_DEVICEOWNER_WHITELIST; private static final Set<String> GLOBAL_SETTINGS_WHITELIST; @@ -193,13 +205,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.ADB_ENABLED); GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME); GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.AUTO_TIME_ZONE); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.BLUETOOTH_ON); GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.DATA_ROAMING); GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.DEVELOPMENT_SETTINGS_ENABLED); GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.MODE_RINGER); GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.NETWORK_PREFERENCE); GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.USB_MASS_STORAGE_ENABLED); - GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_ON); GLOBAL_SETTINGS_WHITELIST.add(Settings.Global.WIFI_SLEEP_POLICY); } @@ -1138,13 +1148,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 { @@ -1518,11 +1530,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // a sanity check in case the two get out of sync; this should // never normally happen. LockPatternUtils utils = new LockPatternUtils(mContext); - if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) { + if (utils.getActivePasswordQuality(userHandle) < policy.mActivePasswordQuality) { Slog.w(LOG_TAG, "Active password quality 0x" + Integer.toHexString(policy.mActivePasswordQuality) + " does not match actual quality 0x" - + Integer.toHexString(utils.getActivePasswordQuality())); + + Integer.toHexString(utils.getActivePasswordQuality(userHandle))); policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; policy.mActivePasswordLength = 0; policy.mActivePasswordUpperCase = 0; @@ -1578,15 +1590,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { void syncDeviceCapabilitiesLocked(DevicePolicyData policy) { // Ensure the status of the camera is synced down to the system. Interested native services // should monitor this value and act accordingly. - boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false); + String cameraPropertyForUser = SYSTEM_PROP_DISABLE_CAMERA_PREFIX + policy.mUserHandle; + boolean systemState = SystemProperties.getBoolean(cameraPropertyForUser, false); boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle); if (cameraDisabled != systemState) { long token = Binder.clearCallingIdentity(); try { String value = cameraDisabled ? "1" : "0"; if (DBG) Slog.v(LOG_TAG, "Change in camera state [" - + SYSTEM_PROP_DISABLE_CAMERA + "] = " + value); - SystemProperties.set(SYSTEM_PROP_DISABLE_CAMERA, value); + + cameraPropertyForUser + "] = " + value); + SystemProperties.set(cameraPropertyForUser, value); } finally { Binder.restoreCallingIdentity(token); } @@ -1897,7 +1910,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; } @@ -1913,17 +1926,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordQuality(ComponentName who, int quality, int userHandle) { + public void setPasswordQuality(ComponentName who, int quality) { if (!mHasFeature) { return; } + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); validateQualityConstant(quality); - enforceCrossUserPermission(userHandle); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.passwordQuality != quality) { @@ -1962,15 +1973,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) { + public void setPasswordMinimumLength(ComponentName who, int length) { if (!mHasFeature) { return; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordLength != length) { @@ -2009,15 +2018,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) { + public void setPasswordHistoryLength(ComponentName who, int length) { if (!mHasFeature) { return; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.passwordHistoryLength != length) { @@ -2056,18 +2063,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) { + public void setPasswordExpirationTimeout(ComponentName who, long timeout) { if (!mHasFeature) { return; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(who, "ComponentName is null"); + Preconditions.checkArgumentNonnegative(timeout, "Timeout must be >= 0 ms"); + final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } - if (timeout < 0) { - throw new IllegalArgumentException("Timeout must be >= 0 ms"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD); // Calling this API automatically bumps the expiration date @@ -2225,15 +2228,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) { + public void setPasswordMinimumUpperCase(ComponentName who, int length) { if (!mHasFeature) { return; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordUpperCase != length) { @@ -2272,12 +2273,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordMinimumLowerCase(ComponentName who, int length, int userHandle) { - enforceCrossUserPermission(userHandle); + public void setPasswordMinimumLowerCase(ComponentName who, int length) { + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordLowerCase != length) { @@ -2316,15 +2315,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) { + public void setPasswordMinimumLetters(ComponentName who, int length) { if (!mHasFeature) { return; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordLetters != length) { @@ -2363,15 +2360,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) { + public void setPasswordMinimumNumeric(ComponentName who, int length) { if (!mHasFeature) { return; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordNumeric != length) { @@ -2410,15 +2405,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) { + public void setPasswordMinimumSymbols(ComponentName who, int length) { if (!mHasFeature) { return; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordSymbols != length) { @@ -2457,15 +2450,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) { + public void setPasswordMinimumNonLetter(ComponentName who, int length) { if (!mHasFeature) { return; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordNonLetter != length) { @@ -2521,8 +2512,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. - getActiveAdminForCallerLocked(null, - DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); + getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle) || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) { return false; @@ -2555,15 +2545,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) { + public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) { if (!mHasFeature) { return; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. getActiveAdminForCallerLocked(who, @@ -2631,11 +2619,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return strictestAdmin; } - public boolean resetPassword(String passwordOrNull, int flags, int userHandle) { + public boolean resetPassword(String passwordOrNull, int flags) { if (!mHasFeature) { return false; } - enforceCrossUserPermission(userHandle); + final int userHandle = UserHandle.getCallingUserId(); enforceNotManagedProfile(userHandle, "reset the password"); String password = passwordOrNull != null ? passwordOrNull : ""; @@ -2744,9 +2732,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { try { LockPatternUtils utils = new LockPatternUtils(mContext); if (!TextUtils.isEmpty(password)) { - utils.saveLockPassword(password, quality, false, userHandle); + utils.saveLockPassword(password, quality, userHandle); } else { - utils.clearLock(false, userHandle); + utils.clearLock(userHandle); } boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0; if (requireEntry) { @@ -2766,15 +2754,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return true; } - public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) { + public void setMaximumTimeToLock(ComponentName who, long timeMs) { if (!mHasFeature) { return; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_FORCE_LOCK); if (ap.maximumTimeToUnlock != timeMs) { @@ -2953,9 +2939,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean installKeyPair(ComponentName who, byte[] privKey, byte[] cert, String alias) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); } @@ -2980,6 +2964,63 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return false; } + @Override + public void choosePrivateKeyAlias(final int uid, final String host, int port, final String url, + final String alias, final IBinder response) { + // Caller UID needs to be trusted, so we restrict this method to SYSTEM_UID callers. + if (UserHandle.getAppId(Binder.getCallingUid()) != Process.SYSTEM_UID) { + return; + } + + final UserHandle caller = Binder.getCallingUserHandle(); + final ComponentName profileOwner = getProfileOwner(caller.getIdentifier()); + + if (profileOwner == null) { + sendPrivateKeyAliasResponse(null, response); + return; + } + + Intent intent = new Intent(DeviceAdminReceiver.ACTION_CHOOSE_PRIVATE_KEY_ALIAS); + intent.setComponent(profileOwner); + intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_SENDER_UID, uid); + intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_HOST, host); + intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_PORT, port); + intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_URL, url); + intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_ALIAS, alias); + intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE, response); + + final long id = Binder.clearCallingIdentity(); + try { + mContext.sendOrderedBroadcastAsUser(intent, caller, null, new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + final String chosenAlias = getResultData(); + sendPrivateKeyAliasResponse(chosenAlias, response); + } + }, null, Activity.RESULT_OK, null, null); + } finally { + Binder.restoreCallingIdentity(id); + } + } + + private void sendPrivateKeyAliasResponse(final String alias, final IBinder responseBinder) { + final IKeyChainAliasCallback keyChainAliasResponse = + IKeyChainAliasCallback.Stub.asInterface(responseBinder); + new AsyncTask<Void, Void, Void>() { + @Override + protected Void doInBackground(Void... unused) { + try { + keyChainAliasResponse.alias(alias); + } catch (Exception e) { + // Catch everything (not just RemoteException): caller could throw a + // RuntimeException back across processes. + Log.e(LOG_TAG, "error while responding to callback", e); + } + return null; + } + }.execute(); + } + private void wipeDataLocked(boolean wipeExtRequested, String reason) { // If the SD card is encrypted and non-removable, we have to force a wipe. boolean forceExtWipe = !Environment.isExternalStorageRemovable() && isExtStorageEncrypted(); @@ -3233,15 +3274,12 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } public ComponentName setGlobalProxy(ComponentName who, String proxySpec, - String exclusionList, int userHandle) { + String exclusionList) { if (!mHasFeature) { return null; } - enforceCrossUserPermission(userHandle); synchronized(this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } + Preconditions.checkNotNull(who, "ComponentName is null"); // Only check if owner has set global proxy. We don't allow other users to set it. DevicePolicyData policy = getUserData(UserHandle.USER_OWNER); @@ -3263,7 +3301,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // If the user is not the owner, don't set the global proxy. Fail silently. if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) { Slog.w(LOG_TAG, "Only the owner is allowed to set the global proxy. User " - + userHandle + " is not permitted."); + + UserHandle.getCallingUserId() + " is not permitted."); return null; } if (proxySpec == null) { @@ -3373,16 +3411,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Set the storage encryption request for a single admin. Returns the new total request * status (for all admins). */ - public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) { + public int setStorageEncryption(ComponentName who, boolean encrypt) { if (!mHasFeature) { return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { // Check for permissions - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } // Only owner can set storage encryption if (userHandle != UserHandle.USER_OWNER || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) { @@ -3509,15 +3545,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * Set whether the screen capture is disabled for the user managed by the specified admin. */ - public void setScreenCaptureDisabled(ComponentName who, int userHandle, boolean disabled) { + public void setScreenCaptureDisabled(ComponentName who, boolean disabled) { if (!mHasFeature) { return; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); if (ap.disableScreenCapture != disabled) { @@ -3568,15 +3602,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * Set whether auto time is required by the specified admin (must be device owner). */ - public void setAutoTimeRequired(ComponentName who, int userHandle, boolean required) { + public void setAutoTimeRequired(ComponentName who, boolean required) { if (!mHasFeature) { return; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin admin = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); if (admin.requireAutoTime != required) { @@ -3612,22 +3644,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * The system property used to share the state of the camera. The native camera service - * is expected to read this property and act accordingly. + * is expected to read this property and act accordingly. The userId should be appended + * to this key. */ - public static final String SYSTEM_PROP_DISABLE_CAMERA = "sys.secpolicy.camera.disabled"; + public static final String SYSTEM_PROP_DISABLE_CAMERA_PREFIX = "sys.secpolicy.camera.off_"; /** * Disables all device cameras according to the specified admin. */ - public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) { + public void setCameraDisabled(ComponentName who, boolean disabled) { if (!mHasFeature) { return; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA); if (ap.disableCamera != disabled) { @@ -3668,16 +3699,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * Selectively disable keyguard features. */ - public void setKeyguardDisabledFeatures(ComponentName who, int which, int userHandle) { + public void setKeyguardDisabledFeatures(ComponentName who, int which) { if (!mHasFeature) { return; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); enforceNotManagedProfile(userHandle, "disable keyguard features"); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES); if (ap.disabledKeyguardFeatures != which) { @@ -3821,9 +3850,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void clearDeviceOwner(String packageName) { - if (packageName == null) { - throw new NullPointerException("packageName is null"); - } + Preconditions.checkNotNull(packageName, "packageName is null"); try { int uid = mContext.getPackageManager().getPackageUid(packageName, 0); if (uid != Binder.getCallingUid()) { @@ -3850,6 +3877,110 @@ 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(ComponentName who) { + if (!mHasFeature) { + return; + } + Preconditions.checkNotNull(who, "ComponentName is null"); + + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, UserHandle.getCallingUserId()); + + if (admin.getUid() != Binder.getCallingUid()) { + throw new SecurityException("Admin " + who + " is not owned by uid " + + Binder.getCallingUid()); + } + + if (!isDeviceInitializer(admin.info.getPackageName()) + && !isDeviceOwner(admin.info.getPackageName())) { + throw new SecurityException( + "clearDeviceInitializer can only be called by the device initializer/owner"); + } + 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) { return false; @@ -3922,7 +4053,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Bundle userRestrictions = mUserManager.getUserRestrictions(); mUserManager.setUserRestrictions(new Bundle(), userHandle); if (userRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)) { - audioManager.setMasterMute(false); + audioManager.setMasterMute(false, 0); } if (userRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE)) { audioManager.setMicrophoneMute(false); @@ -3944,16 +4075,58 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void setProfileEnabled(ComponentName who) { + public boolean setUserEnabled(ComponentName who) { if (!mHasFeature) { - return; + return false; } - final int userHandle = UserHandle.getCallingUserId(); synchronized (this) { - // Check for permissions 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) { + return; + } + Preconditions.checkNotNull(who, "ComponentName is null"); + final int userHandle = UserHandle.getCallingUserId(); + synchronized (this) { // Check if this is the profile owner who is calling getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); int userId = UserHandle.getCallingUserId(); @@ -3975,12 +4148,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void setProfileName(ComponentName who, String profileName) { + Preconditions.checkNotNull(who, "ComponentName is null"); int userId = UserHandle.getCallingUserId(); - - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } - // Check if this is the profile owner (includes device owner). getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); @@ -4042,16 +4211,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } /** - * Device owner can only be set on an unprovisioned device, unless it was initiated by "adb", in - * which case we allow it if no account is associated with the device. + * Device owner can only be set on an unprovisioned device. However, if initiated via "adb", + * we also allow it if no accounts or additional users are present on the device. */ private boolean allowedToSetDeviceOwnerOnDevice() { - int callingId = Binder.getCallingUid(); - if (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID) { - return AccountManager.get(mContext).getAccounts().length == 0; - } else { - return !hasUserSetupCompleted(UserHandle.USER_OWNER); + if (!hasUserSetupCompleted(UserHandle.USER_OWNER)) { + return true; } + + int callingId = Binder.getCallingUid(); + return (callingId == Process.SHELL_UID || callingId == Process.ROOT_UID) + && mUserManager.getUserCount() == 1 + && AccountManager.get(mContext).getAccounts().length == 0; } private void enforceCrossUserPermission(int userHandle) { @@ -4128,7 +4299,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { p.println("Current Device Policy Manager state:"); - + if (mDeviceOwner != null) { + mDeviceOwner.dump(" ", pw); + } int userCount = mUserData.size(); for (int u = 0; u < userCount; u++) { DevicePolicyData policy = getUserData(mUserData.keyAt(u)); @@ -4156,12 +4329,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void addPersistentPreferredActivity(ComponentName who, IntentFilter filter, ComponentName activity) { + Preconditions.checkNotNull(who, "ComponentName is null"); final int userHandle = UserHandle.getCallingUserId(); - synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); IPackageManager pm = AppGlobals.getPackageManager(); @@ -4178,12 +4348,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void clearPackagePersistentPreferredActivities(ComponentName who, String packageName) { + Preconditions.checkNotNull(who, "ComponentName is null"); final int userHandle = UserHandle.getCallingUserId(); - synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); IPackageManager pm = AppGlobals.getPackageManager(); @@ -4200,12 +4367,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void setApplicationRestrictions(ComponentName who, String packageName, Bundle settings) { + Preconditions.checkNotNull(who, "ComponentName is null"); final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId()); - synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); long id = Binder.clearCallingIdentity(); @@ -4218,19 +4382,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } public void setTrustAgentConfiguration(ComponentName admin, ComponentName agent, - PersistableBundle args, int userHandle) { + PersistableBundle args) { if (!mHasFeature) { return; } - enforceCrossUserPermission(userHandle); + Preconditions.checkNotNull(admin, "admin is null"); + Preconditions.checkNotNull(agent, "agent is null"); + final int userHandle = UserHandle.getCallingUserId(); enforceNotManagedProfile(userHandle, "set trust agent configuration"); synchronized (this) { - if (admin == null) { - throw new NullPointerException("admin is null"); - } - if (agent == null) { - throw new NullPointerException("agent is null"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES); ap.trustAgentInfos.put(agent.flattenToString(), new TrustAgentInfo(args)); @@ -4244,10 +4404,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return null; } + Preconditions.checkNotNull(agent, "agent null"); enforceCrossUserPermission(userHandle); - if (agent == null) { - throw new NullPointerException("agent is null"); - } synchronized (this) { final String componentName = agent.flattenToString(); @@ -4300,10 +4458,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void setRestrictionsProvider(ComponentName who, ComponentName permissionProvider) { + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); int userHandle = UserHandle.getCallingUserId(); @@ -4325,11 +4481,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } public void addCrossProfileIntentFilter(ComponentName who, IntentFilter filter, int flags) { + Preconditions.checkNotNull(who, "ComponentName is null"); int callingUserId = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); IPackageManager pm = AppGlobals.getPackageManager(); @@ -4352,11 +4506,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } public void clearCrossProfileIntentFilters(ComponentName who) { + Preconditions.checkNotNull(who, "ComponentName is null"); int callingUserId = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); IPackageManager pm = AppGlobals.getPackageManager(); long id = Binder.clearCallingIdentity(); @@ -4397,8 +4549,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { try { ApplicationInfo applicationInfo = pm.getApplicationInfo(enabledPackage, PackageManager.GET_UNINSTALLED_PACKAGES, userIdToCheck); - systemService = (applicationInfo.flags - & ApplicationInfo.FLAG_SYSTEM) != 0; + systemService = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; } catch (RemoteException e) { Log.i(LOG_TAG, "Can't talk to package managed", e); } @@ -4427,9 +4578,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return false; } - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } + Preconditions.checkNotNull(who, "ComponentName is null"); if (packageList != null) { int userId = UserHandle.getCallingUserId(); @@ -4474,10 +4623,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return null; } - - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { ActiveAdmin admin = getActiveAdminForCallerLocked(who, @@ -4532,15 +4678,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { IPackageManager pm = AppGlobals.getPackageManager(); if (installedServices != null) { for (AccessibilityServiceInfo service : installedServices) { - String packageName = service.getResolveInfo().serviceInfo.packageName; - try { - ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, - PackageManager.GET_UNINSTALLED_PACKAGES, userId); - if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { - result.add(packageName); - } - } catch (RemoteException e) { - Log.i(LOG_TAG, "Accessibility service in missing package", e); + ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo; + ApplicationInfo applicationInfo = serviceInfo.applicationInfo; + if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + result.add(serviceInfo.packageName); } } } @@ -4587,9 +4728,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return false; } - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } + Preconditions.checkNotNull(who, "ComponentName is null"); // TODO When InputMethodManager supports per user calls remove // this restriction. @@ -4632,10 +4771,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return null; } - - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { ActiveAdmin admin = getActiveAdminForCallerLocked(who, @@ -4691,16 +4827,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { IPackageManager pm = AppGlobals.getPackageManager(); if (imes != null) { for (InputMethodInfo ime : imes) { - String packageName = ime.getPackageName(); - try { - ApplicationInfo applicationInfo = pm.getApplicationInfo( - packageName, PackageManager.GET_UNINSTALLED_PACKAGES, - userId); - if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { - result.add(packageName); - } - } catch (RemoteException e) { - Log.i(LOG_TAG, "Input method for missing package", e); + ServiceInfo serviceInfo = ime.getServiceInfo(); + ApplicationInfo applicationInfo = serviceInfo.applicationInfo; + if ((applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) { + result.add(serviceInfo.packageName); } } } @@ -4714,10 +4844,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public UserHandle createUser(ComponentName who, String name) { + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); long id = Binder.clearCallingIdentity(); @@ -4768,10 +4896,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean removeUser(ComponentName who, UserHandle userHandle) { + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); long id = Binder.clearCallingIdentity(); @@ -4785,10 +4911,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean switchUser(ComponentName who, UserHandle userHandle) { + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); long id = Binder.clearCallingIdentity(); @@ -4809,12 +4933,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public Bundle getApplicationRestrictions(ComponentName who, String packageName) { + Preconditions.checkNotNull(who, "ComponentName is null"); final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId()); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); long id = Binder.clearCallingIdentity(); @@ -4828,12 +4950,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void setUserRestriction(ComponentName who, String key, boolean enabled) { + Preconditions.checkNotNull(who, "ComponentName is null"); final UserHandle user = new UserHandle(UserHandle.getCallingUserId()); final int userHandle = user.getIdentifier(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); boolean isDeviceOwner = isDeviceOwner(activeAdmin.info.getPackageName()); @@ -4841,6 +4961,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { && DEVICE_OWNER_USER_RESTRICTIONS.contains(key)) { throw new SecurityException("Profile owners cannot set user restriction " + key); } + if (IMMUTABLE_USER_RESTRICTIONS.contains(key)) { + throw new SecurityException("User restriction " + key + " cannot be changed"); + } boolean alreadyRestricted = mUserManager.hasUserRestriction(key, user); IAudioService iAudioService = null; @@ -4855,7 +4978,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) { iAudioService.setMicrophoneMute(true, who.getPackageName()); } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) { - iAudioService.setMasterMute(true, 0, who.getPackageName(), null); + iAudioService.setMasterMute(true, 0, who.getPackageName()); } } catch (RemoteException re) { Slog.e(LOG_TAG, "Failed to talk to AudioService.", re); @@ -4920,7 +5043,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) { iAudioService.setMicrophoneMute(false, who.getPackageName()); } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) { - iAudioService.setMasterMute(false, 0, who.getPackageName(), null); + iAudioService.setMasterMute(false, 0, who.getPackageName()); } } catch (RemoteException re) { Slog.e(LOG_TAG, "Failed to talk to AudioService.", re); @@ -4933,11 +5056,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean setApplicationHidden(ComponentName who, String packageName, boolean hidden) { + Preconditions.checkNotNull(who, "ComponentName is null"); int callingUserId = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); long id = Binder.clearCallingIdentity(); @@ -4956,11 +5077,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean isApplicationHidden(ComponentName who, String packageName) { + Preconditions.checkNotNull(who, "ComponentName is null"); int callingUserId = UserHandle.getCallingUserId(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); long id = Binder.clearCallingIdentity(); @@ -4979,11 +5098,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void enableSystemApp(ComponentName who, String packageName) { + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } - // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); @@ -5024,11 +5140,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public int enableSystemAppWithIntent(ComponentName who, Intent intent) { + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } - // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); @@ -5056,15 +5169,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (activitiesToEnable != null) { for (ResolveInfo info : activitiesToEnable) { if (info.activityInfo != null) { - - if (!isSystemApp(pm, info.activityInfo.packageName, primaryUser.id)) { - throw new IllegalArgumentException( - "Only system apps can be enabled this way."); + String packageName = info.activityInfo.packageName; + if (isSystemApp(pm, packageName, primaryUser.id)) { + numberOfAppsInstalled++; + pm.installExistingPackageAsUser(packageName, userId); + } else { + Slog.d(LOG_TAG, "Not enabling " + packageName + " since is not a" + + " system app"); } - - - numberOfAppsInstalled++; - pm.installExistingPackageAsUser(info.activityInfo.packageName, userId); } } } @@ -5083,7 +5195,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { throws RemoteException { ApplicationInfo appInfo = pm.getApplicationInfo(packageName, GET_UNINSTALLED_PACKAGES, userId); - return (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) > 0; + if (appInfo == null) { + throw new IllegalArgumentException("The application " + packageName + + " is not present on this device"); + } + return (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0; } @Override @@ -5092,10 +5208,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return; } + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); if (disabled) { @@ -5133,12 +5247,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void setUninstallBlocked(ComponentName who, String packageName, boolean uninstallBlocked) { + Preconditions.checkNotNull(who, "ComponentName is null"); final int userId = UserHandle.getCallingUserId(); - synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); long id = Binder.clearCallingIdentity(); @@ -5185,10 +5296,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return; } + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin admin = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); if (admin.disableCallerId != disabled) { @@ -5203,12 +5312,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (!mHasFeature) { return false; } - + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } - ActiveAdmin admin = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); return admin.disableCallerId; @@ -5229,13 +5334,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Sets which packages may enter lock task mode. * * This function can only be called by the device owner. - * @param components The list of components allowed to enter lock task mode. + * @param packages The list of packages allowed to enter lock task mode. */ public void setLockTaskPackages(ComponentName who, String[] packages) throws SecurityException { + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); int userHandle = Binder.getCallingUserHandle().getIdentifier(); @@ -5257,15 +5360,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * This function returns the list of components allowed to start the task lock mode. */ public String[] getLockTaskPackages(ComponentName who) { + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); int userHandle = Binder.getCallingUserHandle().getIdentifier(); DevicePolicyData policy = getUserData(userHandle); - return policy.mLockTaskPackages.toArray(new String[0]); + return policy.mLockTaskPackages.toArray(new String[policy.mLockTaskPackages.size()]); } } @@ -5321,16 +5422,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void setGlobalSetting(ComponentName who, String setting, String value) { final ContentResolver contentResolver = mContext.getContentResolver(); + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER); if (!GLOBAL_SETTINGS_WHITELIST.contains(setting)) { - throw new SecurityException(String.format( - "Permission denial: device owners cannot update %1$s", setting)); + // BLUETOOTH_ON and WIFI_ON used to be supported but not any more. We do not want to + // throw a SecurityException not to break apps. + if (!Settings.Global.BLUETOOTH_ON.equals(setting) + && !Settings.Global.WIFI_ON.equals(setting)) { + throw new SecurityException(String.format( + "Permission denial: device owners cannot update %1$s", setting)); + } } long id = Binder.clearCallingIdentity(); @@ -5344,13 +5448,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void setSecureSetting(ComponentName who, String setting, String value) { + Preconditions.checkNotNull(who, "ComponentName is null"); int callingUserId = UserHandle.getCallingUserId(); final ContentResolver contentResolver = mContext.getContentResolver(); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } ActiveAdmin activeAdmin = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); @@ -5375,18 +5477,14 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void setMasterVolumeMuted(ComponentName who, boolean on) { - final ContentResolver contentResolver = mContext.getContentResolver(); - + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); IAudioService iAudioService = IAudioService.Stub.asInterface( ServiceManager.getService(Context.AUDIO_SERVICE)); - try{ - iAudioService.setMasterMute(on, 0, who.getPackageName(), null); + try { + iAudioService.setMasterMute(on, 0, who.getPackageName()); } catch (RemoteException re) { Slog.e(LOG_TAG, "Failed to setMasterMute", re); } @@ -5395,12 +5493,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public boolean isMasterVolumeMuted(ComponentName who) { - final ContentResolver contentResolver = mContext.getContentResolver(); - + Preconditions.checkNotNull(who, "ComponentName is null"); synchronized (this) { - if (who == null) { - throw new NullPointerException("ComponentName is null"); - } getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); AudioManager audioManager = @@ -5409,6 +5503,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + @Override + public void setUserIcon(ComponentName who, Bitmap icon) { + synchronized (this) { + Preconditions.checkNotNull(who, "ComponentName is null"); + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + + int userId = UserHandle.getCallingUserId(); + long id = Binder.clearCallingIdentity(); + try { + mUserManager.setUserIcon(userId, icon); + } finally { + restoreCallingIdentity(id); + } + } + } + /** * We need to update the internal state of whether a user has completed setup once. After * that, we ignore any changes that reset the Settings.Secure.USER_SETUP_COMPLETE changes |