diff --git a/core/java/android/app/admin/DevicePolicyManagerInternal.java b/core/java/android/app/admin/DevicePolicyManagerInternal.java index 0a0d77d2a4655..4270e16b32953 100644 --- a/core/java/android/app/admin/DevicePolicyManagerInternal.java +++ b/core/java/android/app/admin/DevicePolicyManagerInternal.java @@ -16,6 +16,8 @@ package android.app.admin; +import android.os.Bundle; + import java.util.List; /** @@ -69,4 +71,13 @@ public abstract class DevicePolicyManagerInternal { * @return true if the uid is an active admin with the given policy. */ public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy); + + /** + * Takes a {@link Bundle} containing "base" user restrictions stored in + * {@link com.android.server.pm.UserManagerService}, mixes restrictions set by the device owner + * and the profile owner and returns the merged restrictions. + * + * This method always returns a new {@link Bundle}. + */ + public abstract Bundle getComposedUserRestrictions(int userId, Bundle inBundle); } diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl index 3ade170b9269c..12cac85308c59 100644 --- a/core/java/android/os/IUserManager.aidl +++ b/core/java/android/os/IUserManager.aidl @@ -55,14 +55,12 @@ interface IUserManager { int getUserHandle(int userSerialNumber); Bundle getUserRestrictions(int userHandle); boolean hasUserRestriction(in String restrictionKey, int userHandle); - void setUserRestrictions(in Bundle restrictions, int userHandle); void setUserRestriction(String key, boolean value, int userId); void setSystemControlledUserRestriction(String key, boolean value, int userId); void setApplicationRestrictions(in String packageName, in Bundle restrictions, int userHandle); Bundle getApplicationRestrictions(in String packageName); Bundle getApplicationRestrictionsForUser(in String packageName, int userHandle); - void removeRestrictions(); void setDefaultGuestRestrictions(in Bundle restrictions); Bundle getDefaultGuestRestrictions(); boolean markGuestForDeletion(int userHandle); diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index 1c1575e06f7e0..909d33c442a5e 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -21,6 +21,7 @@ import android.annotation.SystemApi; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.admin.DevicePolicyManager; +import android.content.ComponentName; import android.content.Context; import android.content.pm.UserInfo; import android.content.res.Resources; @@ -55,7 +56,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts"; @@ -67,7 +69,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CONFIG_WIFI = "no_config_wifi"; @@ -78,7 +81,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_INSTALL_APPS = "no_install_apps"; @@ -89,7 +93,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_UNINSTALL_APPS = "no_uninstall_apps"; @@ -102,7 +107,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_SHARE_LOCATION = "no_share_location"; @@ -114,7 +120,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_INSTALL_UNKNOWN_SOURCES = "no_install_unknown_sources"; @@ -127,7 +134,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth"; @@ -139,7 +147,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_USB_FILE_TRANSFER = "no_usb_file_transfer"; @@ -150,7 +159,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CONFIG_CREDENTIALS = "no_config_credentials"; @@ -163,7 +173,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_REMOVE_USER = "no_remove_user"; @@ -174,7 +185,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_DEBUGGING_FEATURES = "no_debugging_features"; @@ -187,7 +199,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CONFIG_VPN = "no_config_vpn"; @@ -199,7 +212,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CONFIG_TETHERING = "no_config_tethering"; @@ -213,7 +227,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_NETWORK_RESET = "no_network_reset"; @@ -227,7 +242,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_FACTORY_RESET = "no_factory_reset"; @@ -241,7 +257,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_ADD_USER = "no_add_user"; @@ -252,7 +269,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String ENSURE_VERIFY_APPS = "ensure_verify_apps"; @@ -266,7 +284,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts"; @@ -280,7 +299,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CONFIG_MOBILE_NETWORKS = "no_config_mobile_networks"; @@ -300,7 +320,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_APPS_CONTROL = "no_control_apps"; @@ -312,7 +333,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_MOUNT_PHYSICAL_MEDIA = "no_physical_media"; @@ -324,7 +346,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_UNMUTE_MICROPHONE = "no_unmute_microphone"; @@ -336,7 +359,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_ADJUST_VOLUME = "no_adjust_volume"; @@ -350,7 +374,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls"; @@ -361,7 +386,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_SMS = "no_sms"; @@ -373,7 +399,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_FUN = "no_fun"; @@ -393,7 +420,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CREATE_WINDOWS = "no_create_windows"; @@ -406,7 +434,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_CROSS_PROFILE_COPY_PASTE = "no_cross_profile_copy_paste"; @@ -417,7 +446,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_OUTGOING_BEAM = "no_outgoing_beam"; @@ -426,7 +456,8 @@ public class UserManager { * Hidden user restriction to disallow access to wallpaper manager APIs. This user restriction * is always set for managed profiles. * @hide - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_WALLPAPER = "no_wallpaper"; @@ -438,7 +469,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String DISALLOW_SAFE_BOOT = "no_safe_boot"; @@ -447,7 +479,8 @@ public class UserManager { * Specifies if a user is not allowed to record audio. This restriction is always enabled for * background users. The default value is false. * - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() * @hide */ @@ -466,7 +499,8 @@ public class UserManager { * *

Key for user restrictions. *

Type: Boolean - * @see #setUserRestrictions(Bundle) + * @see DevicePolicyManager#addUserRestriction(ComponentName, String) + * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) * @see #getUserRestrictions() */ public static final String ALLOW_PARENT_PROFILE_APP_LINKING @@ -740,36 +774,20 @@ public class UserManager { } /** - * Sets all the user-wide restrictions for this user. - * Requires the MANAGE_USERS permission. - * @param restrictions the Bundle containing all the restrictions. - * @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction( - * android.content.ComponentName, String)} or - * {@link android.app.admin.DevicePolicyManager#clearUserRestriction( - * android.content.ComponentName, String)} instead. + * This will no longer work. Use {@link #setUserRestriction(String, boolean)} instead. */ @Deprecated public void setUserRestrictions(Bundle restrictions) { - setUserRestrictions(restrictions, Process.myUserHandle()); + throw new UnsupportedOperationException("This method is no longer supported"); } /** - * Sets all the user-wide restrictions for the specified user. - * Requires the MANAGE_USERS permission. - * @param restrictions the Bundle containing all the restrictions. - * @param userHandle the UserHandle of the user for whom to set the restrictions. - * @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction( - * android.content.ComponentName, String)} or - * {@link android.app.admin.DevicePolicyManager#clearUserRestriction( - * android.content.ComponentName, String)} instead. + * This will no longer work. Use {@link #setUserRestriction(String, boolean, UserHandle)} + * instead. */ @Deprecated public void setUserRestrictions(Bundle restrictions, UserHandle userHandle) { - try { - mService.setUserRestrictions(restrictions, userHandle.getIdentifier()); - } catch (RemoteException re) { - Log.w(TAG, "Could not set user restrictions", re); - } + throw new UnsupportedOperationException("This method is no longer supported"); } /** @@ -784,9 +802,7 @@ public class UserManager { */ @Deprecated public void setUserRestriction(String key, boolean value) { - Bundle bundle = getUserRestrictions(); - bundle.putBoolean(key, value); - setUserRestrictions(bundle); + setUserRestriction(key, value, Process.myUserHandle()); } /** @@ -882,9 +898,8 @@ public class UserManager { try { user = mService.createUser(name, flags); if (user != null && !user.isAdmin()) { - Bundle userRestrictions = mService.getUserRestrictions(user.id); - addDefaultUserRestrictions(userRestrictions); - mService.setUserRestrictions(userRestrictions, user.id); + mService.setUserRestriction(DISALLOW_SMS, true, user.id); + mService.setUserRestriction(DISALLOW_OUTGOING_CALLS, true, user.id); } } catch (RemoteException re) { Log.w(TAG, "Could not create a user", re); @@ -899,27 +914,22 @@ public class UserManager { * @hide */ public UserInfo createGuest(Context context, String name) { - UserInfo guest = createUser(name, UserInfo.FLAG_GUEST); - if (guest != null) { - Settings.Secure.putStringForUser(context.getContentResolver(), - Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id); - try { - Bundle guestRestrictions = mService.getDefaultGuestRestrictions(); - guestRestrictions.putBoolean(DISALLOW_SMS, true); - guestRestrictions.putBoolean(DISALLOW_INSTALL_UNKNOWN_SOURCES, true); - mService.setUserRestrictions(guestRestrictions, guest.id); - } catch (RemoteException re) { - Log.w(TAG, "Could not update guest restrictions"); + UserInfo guest = null; + try { + guest = mService.createUser(name, UserInfo.FLAG_GUEST); + if (guest != null) { + Settings.Secure.putStringForUser(context.getContentResolver(), + Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id); + + mService.setUserRestriction(DISALLOW_SMS, true, guest.id); + mService.setUserRestriction(DISALLOW_INSTALL_UNKNOWN_SOURCES, true, guest.id); } + } catch (RemoteException re) { + Log.w(TAG, "Could not create a user", re); } return guest; } - private static void addDefaultUserRestrictions(Bundle restrictions) { - restrictions.putBoolean(DISALLOW_OUTGOING_CALLS, true); - restrictions.putBoolean(DISALLOW_SMS, true); - } - /** * Creates a user with the specified name and options as a profile of another user. * Requires {@link android.Manifest.permission#MANAGE_USERS} permission. @@ -1465,15 +1475,6 @@ public class UserManager { return false; } - /** @hide */ - public void removeRestrictions() { - try { - mService.removeRestrictions(); - } catch (RemoteException re) { - Log.w(TAG, "Could not change restrictions pin"); - } - } - /** * @hide * Set restrictions that should apply to any future guest user that's created. diff --git a/core/java/android/os/UserManagerInternal.java b/core/java/android/os/UserManagerInternal.java new file mode 100644 index 0000000000000..d7be6d8c6b29b --- /dev/null +++ b/core/java/android/os/UserManagerInternal.java @@ -0,0 +1,63 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package android.os; + +/** + * @hide Only for use within the system server. + */ +public abstract class UserManagerInternal { + /** + * Lock that must be held when calling certain methods in this class. + * + * This is used to avoid dead lock between + * {@link com.android.server.pm.UserManagerService} and + * {@link com.android.server.devicepolicy.DevicePolicyManagerService}. This lock should not + * be newly taken while holding the DPMS lock, which would cause a dead lock. Take this + * lock first before taking the DPMS lock to avoid that. + */ + public abstract Object getUserRestrictionsLock(); + + /** + * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to get + * {@link com.android.server.pm.UserManagerService} to update effective user restrictions. + * + * Must be called while taking the {@link #getUserRestrictionsLock()} lock. + */ + public abstract void updateEffectiveUserRestrictionsRL(int userId); + + /** + * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to get + * {@link com.android.server.pm.UserManagerService} to update effective user restrictions. + * + * Must be called while taking the {@link #getUserRestrictionsLock()} lock. + */ + public abstract void updateEffectiveUserRestrictionsForAllUsersRL(); + + /** + * Returns the "base" user restrictions. + * + * Used by {@link com.android.server.devicepolicy.DevicePolicyManagerService} for upgrading + * from MNC. + */ + public abstract Bundle getBaseUserRestrictions(int userId); + + /** + * Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} for upgrading + * from MNC. + */ + public abstract void setBaseUserRestrictionsByDpmsForMigration(int userId, + Bundle baseRestrictions); +} diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index b36a22e4461f2..4dd73889a6637 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -16,14 +16,15 @@ package com.android.server.pm; -import android.accounts.Account; import android.annotation.NonNull; +import android.annotation.Nullable; import android.app.Activity; import android.app.ActivityManager; import android.app.ActivityManagerInternal; import android.app.ActivityManagerNative; import android.app.IStopUserCallback; import android.app.admin.DevicePolicyManager; +import android.app.admin.DevicePolicyManagerInternal; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; @@ -46,6 +47,7 @@ import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; import android.os.UserManager; +import android.os.UserManagerInternal; import android.os.storage.StorageManager; import android.os.storage.VolumeInfo; import android.system.ErrnoException; @@ -59,9 +61,11 @@ import android.util.SparseBooleanArray; import android.util.TimeUtils; import android.util.Xml; +import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.app.IAppOpsService; import com.android.internal.util.FastXmlSerializer; +import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.LocalServices; @@ -83,11 +87,18 @@ import java.util.List; import libcore.io.IoUtils; +/** + * Service for {@link UserManager}. + * + * Method naming convention: + * - Methods suffixed with "Locked" should be called within the {@code this} lock. + * - Methods suffixed with "RL" should be called within the {@link #mRestrictionsLock} lock. + */ public class UserManagerService extends IUserManager.Stub { private static final String LOG_TAG = "UserManagerService"; - private static final boolean DBG = false; + private static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE private static final String TAG_NAME = "name"; private static final String ATTR_FLAGS = "flags"; @@ -160,7 +171,38 @@ public class UserManagerService extends IUserManager.Stub { private final File mUserListFile; private final SparseArray mUsers = new SparseArray(); - private final SparseArray mUserRestrictions = new SparseArray(); + + private final Object mRestrictionsLock = new Object(); + + /** + * User restrictions set via UserManager. This doesn't include restrictions set by + * device owner / profile owners. + * + * DO NOT Change existing {@link Bundle} in it. When changing a restriction for a user, + * a new {@link Bundle} should always be created and set. This is because a {@link Bundle} + * maybe shared between {@link #mBaseUserRestrictions} and + * {@link #mCachedEffectiveUserRestrictions}, but they should always updated separately. + * (Otherwise we won't be able to detect what restrictions have changed in + * {@link #updateUserRestrictionsInternalRL). + */ + @GuardedBy("mRestrictionsLock") + private final SparseArray mBaseUserRestrictions = new SparseArray<>(); + + /** + * Cached user restrictions that are in effect -- i.e. {@link #mBaseUserRestrictions} combined + * with device / profile owner restrictions. We'll initialize it lazily; use + * {@link #getEffectiveUserRestrictions} to access it. + * + * DO NOT Change existing {@link Bundle} in it. When changing a restriction for a user, + * a new {@link Bundle} should always be created and set. This is because a {@link Bundle} + * maybe shared between {@link #mBaseUserRestrictions} and + * {@link #mCachedEffectiveUserRestrictions}, but they should always updated separately. + * (Otherwise we won't be able to detect what restrictions have changed in + * {@link #updateUserRestrictionsInternalRL). + */ + @GuardedBy("mRestrictionsLock") + private final SparseArray mCachedEffectiveUserRestrictions = new SparseArray<>(); + private final Bundle mGuestRestrictions = new Bundle(); /** @@ -176,6 +218,8 @@ public class UserManagerService extends IUserManager.Stub { private IAppOpsService mAppOpsService; + private final LocalService mLocalService; + private static UserManagerService sInstance; public static UserManagerService getInstance() { @@ -231,6 +275,8 @@ public class UserManagerService extends IUserManager.Stub { sInstance = this; } } + mLocalService = new LocalService(); + LocalServices.addService(UserManagerInternal.class, mLocalService); } void systemReady() { @@ -258,8 +304,9 @@ public class UserManagerService extends IUserManager.Stub { mAppOpsService = IAppOpsService.Stub.asInterface( ServiceManager.getService(Context.APP_OPS_SERVICE)); for (int i = 0; i < mUserIds.length; ++i) { + final int userId = mUserIds[i]; try { - mAppOpsService.setUserRestrictions(mUserRestrictions.get(mUserIds[i]), mUserIds[i]); + mAppOpsService.setUserRestrictions(getEffectiveUserRestrictions(userId), userId); } catch (RemoteException e) { Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions"); } @@ -588,75 +635,171 @@ public class UserManagerService extends IUserManager.Stub { } } - @Override - public boolean hasUserRestriction(String restrictionKey, int userId) { - synchronized (mPackagesLock) { - Bundle restrictions = mUserRestrictions.get(userId); - return restrictions != null && restrictions.getBoolean(restrictionKey); + @GuardedBy("mRestrictionsLock") + private Bundle computeEffectiveUserRestrictionsRL(int userId) { + final DevicePolicyManagerInternal dpmi = + LocalServices.getService(DevicePolicyManagerInternal.class); + final Bundle systemRestrictions = mBaseUserRestrictions.get(userId); + + final Bundle effective; + if (dpmi == null) { + // TODO Make sure it's because DPMS is disabled and not because we called it too early. + effective = systemRestrictions; + } else { + effective = dpmi.getComposedUserRestrictions(userId, systemRestrictions); + } + return effective; + } + + @GuardedBy("mRestrictionsLock") + private void invalidateEffectiveUserRestrictionsRL(int userId) { + if (DBG) { + Log.d(LOG_TAG, "invalidateEffectiveUserRestrictions userId=" + userId); + } + mCachedEffectiveUserRestrictions.remove(userId); + } + + private Bundle getEffectiveUserRestrictions(int userId) { + synchronized (mRestrictionsLock) { + Bundle restrictions = mCachedEffectiveUserRestrictions.get(userId); + if (restrictions == null) { + restrictions = computeEffectiveUserRestrictionsRL(userId); + mCachedEffectiveUserRestrictions.put(userId, restrictions); + } + return restrictions; } } + /** @return a specific user restriction that's in effect currently. */ + @Override + public boolean hasUserRestriction(String restrictionKey, int userId) { + Bundle restrictions = getEffectiveUserRestrictions(userId); + return restrictions != null && restrictions.getBoolean(restrictionKey); + } + + /** + * @return UserRestrictions that are in effect currently. This always returns a new + * {@link Bundle}. + */ @Override public Bundle getUserRestrictions(int userId) { - synchronized (mPackagesLock) { - Bundle restrictions = mUserRestrictions.get(userId); - return restrictions != null ? new Bundle(restrictions) : new Bundle(); - } + Bundle restrictions = getEffectiveUserRestrictions(userId); + return restrictions != null ? new Bundle(restrictions) : new Bundle(); } @Override public void setUserRestriction(String key, boolean value, int userId) { checkManageUsersPermission("setUserRestriction"); - synchronized (mPackagesLock) { - if (!UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS.contains(key)) { - Bundle restrictions = getUserRestrictions(userId); - restrictions.putBoolean(key, value); - setUserRestrictionsInternalLocked(restrictions, userId); - } + if (!UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS.contains(key)) { + setUserRestrictionNoCheck(key, value, userId); } } @Override public void setSystemControlledUserRestriction(String key, boolean value, int userId) { checkSystemOrRoot("setSystemControlledUserRestriction"); - synchronized (mPackagesLock) { - Bundle restrictions = getUserRestrictions(userId); - restrictions.putBoolean(key, value); - setUserRestrictionsInternalLocked(restrictions, userId); + setUserRestrictionNoCheck(key, value, userId); + } + + private void setUserRestrictionNoCheck(String key, boolean value, int userId) { + synchronized (mRestrictionsLock) { + // Note we can't modify Bundles stored in mBaseUserRestrictions directly, so create + // a copy. + final Bundle newRestrictions = new Bundle(); + UserRestrictionsUtils.merge(newRestrictions, mBaseUserRestrictions.get(userId)); + newRestrictions.putBoolean(key, value); + + updateUserRestrictionsInternalRL(newRestrictions, userId); } } - @Override - public void setUserRestrictions(Bundle restrictions, int userId) { - checkManageUsersPermission("setUserRestrictions"); - if (restrictions == null) return; - - synchronized (mPackagesLock) { - final Bundle oldUserRestrictions = mUserRestrictions.get(userId); - // Restore the original state of system controlled restrictions from oldUserRestrictions - for (String key : UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS) { - restrictions.remove(key); - if (oldUserRestrictions.containsKey(key)) { - restrictions.putBoolean(key, oldUserRestrictions.getBoolean(key)); - } - } - setUserRestrictionsInternalLocked(restrictions, userId); + /** + * Optionally updating user restrictions, calculate the effective user restrictions by + * consulting {@link com.android.server.devicepolicy.DevicePolicyManagerService} and also + * apply it to {@link com.android.server.AppOpsService}. + * TODO applyUserRestrictionsLocked() should also apply to system settings. + * + * @param newRestrictions User restrictions to set. If null, only the effective restrictions + * will be updated. Note don't pass an existing Bundle in {@link #mBaseUserRestrictions} + * or {@link #mCachedEffectiveUserRestrictions}; that'll most likely cause a sub + * @param userId target user ID. + */ + @GuardedBy("mRestrictionsLock") + private void updateUserRestrictionsInternalRL( + @Nullable Bundle newRestrictions, int userId) { + if (DBG) { + Log.d(LOG_TAG, "updateUserRestrictionsInternalLocked userId=" + userId + + " bundle=" + newRestrictions); } + final Bundle prevRestrictions = getEffectiveUserRestrictions(userId); + + // Update system restrictions. + if (newRestrictions != null) { + // If newRestrictions == the current one, it's probably a bug. + Preconditions.checkState(mBaseUserRestrictions.get(userId) != newRestrictions); + Preconditions.checkState(mCachedEffectiveUserRestrictions.get(userId) + != newRestrictions); + mBaseUserRestrictions.put(userId, newRestrictions); + } + + mCachedEffectiveUserRestrictions.put( + userId, computeEffectiveUserRestrictionsRL(userId)); + + applyUserRestrictionsRL(userId, mBaseUserRestrictions.get(userId), prevRestrictions); } - private void setUserRestrictionsInternalLocked(Bundle restrictions, int userId) { - final Bundle userRestrictions = mUserRestrictions.get(userId); - userRestrictions.clear(); - userRestrictions.putAll(restrictions); - long token = Binder.clearCallingIdentity(); + @GuardedBy("mRestrictionsLock") + private void applyUserRestrictionsRL(int userId, + Bundle newRestrictions, Bundle prevRestrictions) { + final long token = Binder.clearCallingIdentity(); try { - mAppOpsService.setUserRestrictions(userRestrictions, userId); + mAppOpsService.setUserRestrictions(newRestrictions, userId); } catch (RemoteException e) { Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions"); } finally { Binder.restoreCallingIdentity(token); } - scheduleWriteUserLocked(mUsers.get(userId)); + + // TODO Move the code from DPMS.setUserRestriction(). + } + + @GuardedBy("mRestrictionsLock") + private void updateEffectiveUserRestrictionsRL(int userId) { + updateUserRestrictionsInternalRL(null, userId); + } + + @GuardedBy("mRestrictionsLock") + private void updateEffectiveUserRestrictionsForAllUsersRL() { + // First, invalidate all cached values. + synchronized (mRestrictionsLock) { + mCachedEffectiveUserRestrictions.clear(); + } + // We don't want to call into ActivityManagerNative while taking a lock, so we'll call + // it on a handler. + final Runnable r = new Runnable() { + @Override + public void run() { + // Then get the list of running users. + final int[] runningUsers; + try { + runningUsers = ActivityManagerNative.getDefault().getRunningUserIds(); + } catch (RemoteException e) { + Log.w(LOG_TAG, "Unable to access ActivityManagerNative"); + return; + } + // Then re-calculate the effective restrictions and apply, only for running users. + // It's okay if a new user has started after the getRunningUserIds() call, + // because we'll do the same thing (re-calculate the restrictions and apply) + // when we start a user. + // TODO: "Apply restrictions upon user start hasn't been implemented. Implement it. + synchronized (mRestrictionsLock) { + for (int i = 0; i < runningUsers.length; i++) { + updateUserRestrictionsInternalRL(null, runningUsers[i]); + } + } + } + }; + mHandler.post(r); } /** @@ -926,7 +1069,9 @@ public class UserManagerService extends IUserManager.Stub { mUserVersion = USER_VERSION; Bundle restrictions = new Bundle(); - mUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions); + synchronized (mRestrictionsLock) { + mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions); + } updateUserIdsLocked(); initDefaultGuestRestrictions(); @@ -989,9 +1134,13 @@ public class UserManagerService extends IUserManager.Stub { serializer.startTag(null, TAG_NAME); serializer.text(userInfo.name); serializer.endTag(null, TAG_NAME); - Bundle restrictions = mUserRestrictions.get(userInfo.id); + Bundle restrictions; + synchronized (mRestrictionsLock) { + restrictions = mBaseUserRestrictions.get(userInfo.id); + } if (restrictions != null) { - UserRestrictionsUtils.writeRestrictions(serializer, restrictions, TAG_RESTRICTIONS); + UserRestrictionsUtils + .writeRestrictions(serializer, restrictions, TAG_RESTRICTIONS); } serializer.endTag(null, TAG_USER); @@ -1131,7 +1280,9 @@ public class UserManagerService extends IUserManager.Stub { userInfo.guestToRemove = guestToRemove; userInfo.profileGroupId = profileGroupId; userInfo.restrictedProfileParentId = restrictedProfileParentId; - mUserRestrictions.append(id, restrictions); + synchronized (mRestrictionsLock) { + mBaseUserRestrictions.append(id, restrictions); + } return userInfo; } catch (IOException ioe) { @@ -1333,7 +1484,9 @@ public class UserManagerService extends IUserManager.Stub { scheduleWriteUserLocked(userInfo); updateUserIdsLocked(); Bundle restrictions = new Bundle(); - mUserRestrictions.append(userId, restrictions); + synchronized (mRestrictionsLock) { + mBaseUserRestrictions.append(userId, restrictions); + } } } mPm.newUserCreated(userId); @@ -1616,25 +1769,6 @@ public class UserManagerService extends IUserManager.Stub { } } - @Override - public void removeRestrictions() { - checkManageUsersPermission("remove restrictions"); - final int userHandle = UserHandle.getCallingUserId(); - removeRestrictionsForUser(userHandle, true); - } - - private void removeRestrictionsForUser(final int userHandle, boolean unhideApps) { - synchronized (mPackagesLock) { - // Remove all user restrictions - setUserRestrictions(new Bundle(), userHandle); - // Remove any app restrictions - cleanAppRestrictions(userHandle); - } - if (unhideApps) { - unhideAllInstalledAppsForUser(userHandle); - } - } - private void unhideAllInstalledAppsForUser(final int userHandle) { mHandler.post(new Runnable() { @Override @@ -2062,7 +2196,10 @@ public class UserManagerService extends IUserManager.Stub { } pw.println(" Restrictions:"); UserRestrictionsUtils.dumpRestrictions( - pw, " ", mUserRestrictions.get(user.id)); + pw, " ", mBaseUserRestrictions.get(user.id)); + pw.println(" Effective restrictions:"); + UserRestrictionsUtils.dumpRestrictions( + pw, " ", mCachedEffectiveUserRestrictions.get(user.id)); } pw.println(); pw.println("Guest restrictions:"); @@ -2095,4 +2232,49 @@ public class UserManagerService extends IUserManager.Stub { boolean isInitialized(int userId) { return (getUserInfo(userId).flags & UserInfo.FLAG_INITIALIZED) != 0; } + + private class LocalService extends UserManagerInternal { + + @Override + public Object getUserRestrictionsLock() { + return mRestrictionsLock; + } + + @Override + @GuardedBy("mRestrictionsLock") + public void updateEffectiveUserRestrictionsRL(int userId) { + UserManagerService.this.updateEffectiveUserRestrictionsRL(userId); + } + + @Override + @GuardedBy("mRestrictionsLock") + public void updateEffectiveUserRestrictionsForAllUsersRL() { + UserManagerService.this.updateEffectiveUserRestrictionsForAllUsersRL(); + } + + @Override + public Bundle getBaseUserRestrictions(int userId) { + synchronized (mRestrictionsLock) { + return mBaseUserRestrictions.get(userId); + } + } + + @Override + public void setBaseUserRestrictionsByDpmsForMigration( + int userId, Bundle baseRestrictions) { + synchronized (mRestrictionsLock) { + mBaseUserRestrictions.put(userId, new Bundle(baseRestrictions)); + invalidateEffectiveUserRestrictionsRL(userId); + } + + synchronized (mPackagesLock) { + final UserInfo userInfo = mUsers.get(userId); + if (userInfo != null) { + writeUserLocked(userInfo); + } else { + Slog.w(LOG_TAG, "UserInfo not found for " + userId); + } + } + } + } } diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index db1fd2e28dfac..23e3b35ae3da8 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -86,7 +86,6 @@ public class UserRestrictionsUtils { String tag) throws IOException { serializer.startTag(null, tag); for (String key : USER_RESTRICTIONS) { - // if (restrictions.getBoolean(key) && !NON_PERSIST_USER_RESTRICTIONS.contains(key)) { serializer.attribute(null, key, "true"); @@ -105,6 +104,17 @@ public class UserRestrictionsUtils { } } + public static void merge(Bundle dest, Bundle in) { + if (in == null) { + return; + } + for (String key : in.keySet()) { + if (in.getBoolean(key, false)) { + dest.putBoolean(key, true); + } + } + } + public static void dumpRestrictions(PrintWriter pw, String prefix, Bundle restrictions) { boolean noneSet = true; if (restrictions != null) { @@ -114,9 +124,11 @@ public class UserRestrictionsUtils { noneSet = false; } } - } - if (noneSet) { - pw.println(prefix + "none"); + if (noneSet) { + pw.println(prefix + "none"); + } + } else { + pw.println(prefix + "null"); } } } diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index 8385685cfcdbb..b4c8f966ba711 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -16,6 +16,8 @@ package com.android.server.devicepolicy; +import com.google.android.collect.Sets; + import static android.Manifest.permission.MANAGE_CA_CERTIFICATES; import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX; import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE; @@ -88,6 +90,7 @@ import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; import android.os.UserManager; +import android.os.UserManagerInternal; import android.os.storage.StorageManager; import android.provider.ContactsContract.QuickContact; import android.provider.ContactsInternal; @@ -183,8 +186,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning; private static final int PROFILE_WIPED_NOTIFICATION_ID = 1001; - private static final boolean DBG = false; - private static final String ATTR_PERMISSION_PROVIDER = "permission-provider"; private static final String ATTR_SETUP_COMPLETE = "setup-complete"; private static final String ATTR_PERMISSION_POLICY = "permission-policy"; @@ -274,6 +275,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final Injector mInjector; final IPackageManager mIPackageManager; final UserManager mUserManager; + final UserManagerInternal mUserManagerInternal; final LocalService mLocalService; @@ -357,8 +359,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { getSendingUserId()); if (Intent.ACTION_BOOT_COMPLETED.equals(action) || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) { - if (DBG) Slog.v(LOG_TAG, "Sending password expiration notifications for action " - + action + " for user " + userHandle); + if (VERBOSE_LOG) { + Slog.v(LOG_TAG, "Sending password expiration notifications for action " + + action + " for user " + userHandle); + } mHandler.post(new Runnable() { @Override public void run() { @@ -1014,7 +1018,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { private void handlePackagesChanged(String packageName, int userHandle) { boolean removed = false; - if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle); + if (VERBOSE_LOG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle); DevicePolicyData policy = getUserData(userHandle); synchronized (this) { for (int i = policy.mAdminList.size() - 1; i >= 0; i--) { @@ -1079,6 +1083,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return UserManager.get(mContext); } + UserManagerInternal getUserManagerInternal() { + return LocalServices.getService(UserManagerInternal.class); + } + NotificationManager getNotificationManager() { return mContext.getSystemService(NotificationManager.class); } @@ -1233,6 +1241,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { mOwners = Preconditions.checkNotNull(injector.newOwners()); mUserManager = Preconditions.checkNotNull(injector.getUserManager()); + mUserManagerInternal = Preconditions.checkNotNull(injector.getUserManagerInternal()); mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager()); mLocalService = new LocalService(); @@ -1327,10 +1336,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { mOwners.load(); findOwnerComponentIfNecessaryLocked(); + migrateUserRestrictionsIfNecessaryLocked(); // TODO PO may not have a class name either due to b/17652534. Address that too. updateDeviceOwnerLocked(); + + // TODO Notify UM to update restrictions (?) } } @@ -1350,14 +1362,113 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { if (doComponent == null) { Slog.e(LOG_TAG, "Device-owner isn't registered as device-admin"); } else { - mOwners.setDeviceOwner( + mOwners.setDeviceOwnerWithRestrictionsMigrated( doComponent, mOwners.getDeviceOwnerName(), - mOwners.getDeviceOwnerUserId()); + mOwners.getDeviceOwnerUserId(), + !mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()); mOwners.writeDeviceOwner(); + if (VERBOSE_LOG) { + Log.v(LOG_TAG, "Device owner component filled in"); + } } } + /** + * We didn't use to persist user restrictions for each owners but only persisted in user + * manager. + */ + private void migrateUserRestrictionsIfNecessaryLocked() { + boolean migrated = false; + // Migrate for the DO. Basically all restrictions should be considered to be set by DO, + // except for the "system controlled" ones. + if (mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()) { + if (VERBOSE_LOG) { + Log.v(LOG_TAG, "Migrating DO user restrictions"); + } + migrated = true; + + // Migrate user 0 restrictions to DO, except for "system" restrictions. + final ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked(); + + migrateUserRestrictionsForUser(UserHandle.SYSTEM, deviceOwnerAdmin, + /* exceptionList =*/ UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS); + + mOwners.setDeviceOwnerUserRestrictionsMigrated(); + } + + // Migrate for POs. We have a few more exceptions. + final Set normalExceptionList = Sets.newArraySet( + UserManager.DISALLOW_OUTGOING_CALLS, + UserManager.DISALLOW_SMS); + normalExceptionList.addAll(UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS); + + final Set managedExceptionList = new ArraySet<>(normalExceptionList.size() + 1); + managedExceptionList.addAll(normalExceptionList); + managedExceptionList.add(UserManager.DISALLOW_WALLPAPER); + + for (UserInfo ui : mUserManager.getUsers()) { + final int userId = ui.id; + if (mOwners.getProfileOwnerUserRestrictionsNeedsMigration(userId)) { + if (userId != UserHandle.USER_SYSTEM) { + if (VERBOSE_LOG) { + Log.v(LOG_TAG, "Migrating PO user restrictions for user " + userId); + } + migrated = true; + + final ActiveAdmin profileOwnerAdmin = getProfileOwnerAdminLocked(userId); + + final Set exceptionList = + ui.isManagedProfile() ? managedExceptionList : normalExceptionList; + + migrateUserRestrictionsForUser(ui.getUserHandle(), profileOwnerAdmin, + exceptionList); + } + + mOwners.setProfileOwnerUserRestrictionsMigrated(userId); + } + } + if (VERBOSE_LOG && migrated) { + Log.v(LOG_TAG, "User restrictions migrated."); + } + } + + private void migrateUserRestrictionsForUser(UserHandle user, ActiveAdmin admin, + Set exceptionList) { + final Bundle origRestrictions = mUserManagerInternal.getBaseUserRestrictions( + user.getIdentifier()); + + final Bundle newSystemRestrictions = new Bundle(); + final Bundle newOwnerRestrictions = new Bundle(); + + for (String key : origRestrictions.keySet()) { + if (!origRestrictions.getBoolean(key)) { + continue; + } + if (exceptionList.contains(key)) { + newSystemRestrictions.putBoolean(key, true); + } else { + newOwnerRestrictions.putBoolean(key, true); + } + } + + if (VERBOSE_LOG) { + Log.v(LOG_TAG, "origRestrictions=" + origRestrictions); + Log.v(LOG_TAG, "newSystemRestrictions=" + newSystemRestrictions); + Log.v(LOG_TAG, "newOwnerRestrictions=" + newOwnerRestrictions); + } + mUserManagerInternal.setBaseUserRestrictionsByDpmsForMigration(user.getIdentifier(), + newSystemRestrictions); + + if (admin != null) { + admin.ensureUserRestrictions().clear(); + admin.ensureUserRestrictions().putAll(newOwnerRestrictions); + } else { + Slog.w(LOG_TAG, "ActiveAdmin for DO/PO not found. user=" + user.getIdentifier()); + } + saveSettingsLocked(user.getIdentifier()); + } + private ComponentName findAdminComponentWithPackageLocked(String packageName, int userId) { final DevicePolicyData policy = getUserData(userId); final int n = policy.mAdminList.size(); @@ -1373,7 +1484,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { nFound++; } } - if (nFound > 0) { + if (nFound > 1) { Slog.w(LOG_TAG, "Multiple DA found; assume the first one is DO."); } return found; @@ -1636,6 +1747,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ? mInjector.getDevicePolicyFilePathForSystemUser() + DEVICE_POLICIES_XML : new File(mInjector.environmentGetUserSystemDirectory(userHandle), DEVICE_POLICIES_XML).getAbsolutePath(); + if (VERBOSE_LOG) { + Log.v(LOG_TAG, "Opening " + base); + } return new JournaledFile(new File(base), new File(base + ".tmp")); } @@ -1808,7 +1922,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { try { DeviceAdminInfo dai = findAdmin( ComponentName.unflattenFromString(name), userHandle); - if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid) + if (VERBOSE_LOG + && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid) != userHandle)) { Slog.w(LOG_TAG, "findAdmin returned an incorrect uid " + dai.getActivityInfo().applicationInfo.uid + " for user " @@ -1988,8 +2103,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long token = mInjector.binderClearCallingIdentity(); try { String value = cameraDisabled ? "1" : "0"; - if (DBG) Slog.v(LOG_TAG, "Change in camera state [" - + cameraPropertyForUser + "] = " + value); + if (VERBOSE_LOG) { + Slog.v(LOG_TAG, "Change in camera state [" + + cameraPropertyForUser + "] = " + value); + } mInjector.systemPropertiesSet(cameraPropertyForUser, value); } finally { mInjector.binderRestoreCallingIdentity(token); @@ -4513,8 +4630,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } UserHandle callingUser = mInjector.binderGetCallingUserHandle(); // Check if this is the profile owner who is calling - getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + final ActiveAdmin admin = + getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); synchronized (this) { + admin.userRestrictions = null; clearUserPoliciesLocked(callingUser); final int userId = callingUser.getIdentifier(); mOwners.removeProfileOwner(userId); @@ -4533,38 +4652,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { final long ident = mInjector.binderClearCallingIdentity(); try { - clearUserRestrictions(userHandle); mIPackageManager.updatePermissionFlagsForAllApps( PackageManager.FLAG_PERMISSION_POLICY_FIXED, 0 /* flagValues */, userHandle.getIdentifier()); + // TODO This will not revert audio mute restrictions if they were set. b/24981972 + synchronized (mUserManagerInternal.getUserRestrictionsLock()) { + mUserManagerInternal.updateEffectiveUserRestrictionsRL(userHandle.getIdentifier()); + } } catch (RemoteException re) { } finally { mInjector.binderRestoreCallingIdentity(ident); } } - - private void clearUserRestrictions(UserHandle userHandle) { - Bundle userRestrictions = mUserManager.getUserRestrictions(); - mUserManager.setUserRestrictions(new Bundle(), userHandle); - if (userRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)) { - try { - mInjector.getIAudioService().setMasterMute(true, 0, mContext.getPackageName(), - userHandle.getIdentifier()); - } catch (RemoteException e) { - // Not much we can do here. - } - } - if (userRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE)) { - try { - mInjector.getIAudioService().setMicrophoneMute(true, mContext.getPackageName(), - userHandle.getIdentifier()); - } catch (RemoteException e) { - // Not much we can do here. - } - } - } - @Override public boolean hasUserSetupCompleted() { return hasUserSetupCompleted(UserHandle.getCallingUserId()); @@ -5503,95 +5603,123 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } @Override - public void setUserRestriction(ComponentName who, String key, boolean enabled) { + public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner) { Preconditions.checkNotNull(who, "ComponentName is null"); final int userHandle = mInjector.userHandleGetCallingUserId(); final UserHandle user = new UserHandle(userHandle); - synchronized (this) { - ActiveAdmin activeAdmin = - getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); - boolean isDeviceOwner = isDeviceOwner(who); - if (!isDeviceOwner && userHandle != UserHandle.USER_SYSTEM - && 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); + synchronized (mUserManagerInternal.getUserRestrictionsLock()) { + synchronized (this) { + ActiveAdmin activeAdmin = + getActiveAdminForCallerLocked(who, + DeviceAdminInfo.USES_POLICY_PROFILE_OWNER); + boolean isDeviceOwner = isDeviceOwner(who); + if (!isDeviceOwner && userHandle != UserHandle.USER_SYSTEM + && 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"); + } - long id = mInjector.binderClearCallingIdentity(); - try { - if (enabled && !alreadyRestricted) { - if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) { - mInjector.getIAudioService() - .setMicrophoneMute(true, mContext.getPackageName(), userHandle); - } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) { - mInjector.getIAudioService() - .setMasterMute(true, 0, mContext.getPackageName(), userHandle); - } else if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) { - mInjector.settingsSecurePutIntForUser( - Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0, - userHandle); - } else if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) { - mInjector.settingsSecurePutIntForUser( - Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF, - userHandle); - mInjector.settingsSecurePutStringForUser( - Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "", - userHandle); - } else if (UserManager.DISALLOW_DEBUGGING_FEATURES.equals(key)) { - // Only disable adb if changing for system user, since it is global - // TODO: should this be admin user? - if (userHandle == UserHandle.USER_SYSTEM) { + final long id = mInjector.binderClearCallingIdentity(); + try { + // Original value. + final boolean alreadyRestricted = mUserManager.hasUserRestriction(key, user); + + // Save the restriction to ActiveAdmin. + // TODO When DO sets a restriction, it'll always be treated as device-wide. + // If there'll be a policy that can be set by both, we'll need scoping support, + // and need to have another Bundle in DO active admin to hold restrictions as + // PO. + activeAdmin.ensureUserRestrictions().putBoolean(key, enabledFromThisOwner); + saveSettingsLocked(userHandle); + + // Tell UserManager the new value. Note this needs to be done before calling + // into AudioService, because AS will check AppOps that'll be updated by UM. + if (isDeviceOwner) { + mUserManagerInternal.updateEffectiveUserRestrictionsForAllUsersRL(); + } else { + mUserManagerInternal.updateEffectiveUserRestrictionsRL(userHandle); + } + + // New value. + final boolean enabled = mUserManager.hasUserRestriction(key, user); + + // TODO The rest of the code should move to UserManagerService. + + if (enabled && !alreadyRestricted) { + if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) { + mInjector.getIAudioService() + .setMicrophoneMute(true, mContext.getPackageName(), userHandle); + } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) { + mInjector.getIAudioService() + .setMasterMute(true, 0, mContext.getPackageName(), userHandle); + } else if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) { + mInjector.settingsSecurePutIntForUser( + Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0, + userHandle); + } else if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) { + mInjector.settingsSecurePutIntForUser( + Settings.Secure.LOCATION_MODE, + Settings.Secure.LOCATION_MODE_OFF, + userHandle); + mInjector.settingsSecurePutStringForUser( + Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "", + userHandle); + } else if (UserManager.DISALLOW_DEBUGGING_FEATURES.equals(key)) { + // Only disable adb if changing for system user, since it is global + // TODO: should this be admin user? + if (userHandle == UserHandle.USER_SYSTEM) { + mInjector.settingsGlobalPutStringForUser( + Settings.Global.ADB_ENABLED, "0", userHandle); + } + } else if (UserManager.ENSURE_VERIFY_APPS.equals(key)) { mInjector.settingsGlobalPutStringForUser( - Settings.Global.ADB_ENABLED, "0", userHandle); + Settings.Global.PACKAGE_VERIFIER_ENABLE, "1", + userHandle); + mInjector.settingsGlobalPutStringForUser( + Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, "1", + userHandle); + } else if (UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES.equals(key)) { + mInjector.settingsSecurePutIntForUser( + Settings.Secure.INSTALL_NON_MARKET_APPS, 0, + userHandle); } - } else if (UserManager.ENSURE_VERIFY_APPS.equals(key)) { - mInjector.settingsGlobalPutStringForUser( - Settings.Global.PACKAGE_VERIFIER_ENABLE, "1", - userHandle); - mInjector.settingsGlobalPutStringForUser( - Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, "1", - userHandle); - } else if (UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES.equals(key)) { - mInjector.settingsSecurePutIntForUser( - Settings.Secure.INSTALL_NON_MARKET_APPS, 0, - userHandle); } - } - mUserManager.setUserRestriction(key, enabled, user); - activeAdmin.ensureUserRestrictions().putBoolean(key, enabled); - saveSettingsLocked(userHandle); - if (enabled != alreadyRestricted) { - if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) { - // Send out notifications however as some clients may want to reread the - // value which actually changed due to a restriction having been applied. - final String property = Settings.Secure.SYS_PROP_SETTING_VERSION; - long version = mInjector.systemPropertiesGetLong(property, 0) + 1; - mInjector.systemPropertiesSet(property, Long.toString(version)); + if (enabled != alreadyRestricted) { + if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) { + // Send out notifications however as some clients may want to reread the + // value which actually changed due to a restriction having been + // applied. + final String property = Settings.Secure.SYS_PROP_SETTING_VERSION; + long version = mInjector.systemPropertiesGetLong(property, 0) + 1; + mInjector.systemPropertiesSet(property, Long.toString(version)); - final String name = Settings.Secure.LOCATION_PROVIDERS_ALLOWED; - Uri url = Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name); - mContext.getContentResolver().notifyChange(url, null, true, userHandle); + final String name = Settings.Secure.LOCATION_PROVIDERS_ALLOWED; + Uri url = Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name); + mContext.getContentResolver().notifyChange(url, null, true, userHandle); + } } - } - if (!enabled && alreadyRestricted) { - if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) { - mInjector.getIAudioService() - .setMicrophoneMute(false, mContext.getPackageName(), userHandle); - } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) { - mInjector.getIAudioService() - .setMasterMute(false, 0, mContext.getPackageName(), userHandle); + if (!enabled && alreadyRestricted) { + if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) { + mInjector.getIAudioService() + .setMicrophoneMute(false, mContext.getPackageName(), + userHandle); + } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) { + mInjector.getIAudioService() + .setMasterMute(false, 0, mContext.getPackageName(), userHandle); + } } + } catch (RemoteException re) { + Slog.e(LOG_TAG, "Failed to talk to AudioService.", re); + } finally { + mInjector.binderRestoreCallingIdentity(id); } - } catch (RemoteException re) { - Slog.e(LOG_TAG, "Failed to talk to AudioService.", re); - } finally { - mInjector.binderRestoreCallingIdentity(id); + + sendChangedNotification(userHandle); } - sendChangedNotification(userHandle); } } @@ -5650,7 +5778,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long id = mInjector.binderClearCallingIdentity(); try { - if (DBG) { + if (VERBOSE_LOG) { Slog.v(LOG_TAG, "installing " + packageName + " for " + userId); } @@ -5705,7 +5833,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { 0, // no flags primaryUser.id); - if (DBG) Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable); + if (VERBOSE_LOG) { + Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable); + } int numberOfAppsInstalled = 0; if (activitiesToEnable != null) { for (ResolveInfo info : activitiesToEnable) { @@ -6275,7 +6405,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private final class LocalService extends DevicePolicyManagerInternal { + @VisibleForTesting + final class LocalService extends DevicePolicyManagerInternal { private List mWidgetProviderListeners; @Override @@ -6322,6 +6453,30 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } + @Override + public Bundle getComposedUserRestrictions(int userId, Bundle inBundle) { + synchronized (DevicePolicyManagerService.this) { + final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked(); + final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId); + + final Bundle deviceOwnerRestrictions = + deviceOwner == null ? null : deviceOwner.userRestrictions; + final Bundle profileOwnerRestrictions = + profileOwner == null ? null : profileOwner.userRestrictions; + + if (deviceOwnerRestrictions == null && profileOwnerRestrictions == null) { + // No restrictions to merge. + return inBundle; + } + + final Bundle composed = new Bundle(inBundle); + UserRestrictionsUtils.merge(composed, deviceOwnerRestrictions); + UserRestrictionsUtils.merge(composed, profileOwnerRestrictions); + + return composed; + } + } + private void notifyCrossProfileProvidersChanged(int userId, List packages) { final List listeners; synchronized (DevicePolicyManagerService.this) { diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java index 799267d9bf449..12b3775d3071a 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java @@ -30,7 +30,6 @@ import android.util.Slog; import android.util.Xml; import com.android.internal.util.FastXmlSerializer; -import com.android.internal.util.Preconditions; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -75,6 +74,7 @@ class Owners { private static final String ATTR_PACKAGE = "package"; private static final String ATTR_COMPONENT_NAME = "component"; private static final String ATTR_USERID = "userId"; + private static final String ATTR_USER_RESTRICTIONS_MIGRATED = "userRestrictionsMigrated"; private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy"; @@ -155,7 +155,16 @@ class Owners { Slog.e(TAG, "Invalid user id for device owner user: " + userId); return; } - mDeviceOwner = new OwnerInfo(ownerName, admin); + // For a newly set DO, there's no need for migration. + setDeviceOwnerWithRestrictionsMigrated(admin, ownerName, userId, + /* userRestrictionsMigrated =*/ true); + } + + // Note this should be only called during migration. Normally when DO is set, + // userRestrictionsMigrated should always be true. + void setDeviceOwnerWithRestrictionsMigrated(ComponentName admin, String ownerName, int userId, + boolean userRestrictionsMigrated) { + mDeviceOwner = new OwnerInfo(ownerName, admin, userRestrictionsMigrated); mDeviceOwnerUserId = userId; } @@ -165,7 +174,9 @@ class Owners { } void setProfileOwner(ComponentName admin, String ownerName, int userId) { - mProfileOwners.put(userId, new OwnerInfo(ownerName, admin)); + // For a newly set PO, there's no need for migration. + mProfileOwners.put(userId, new OwnerInfo(ownerName, admin, + /* userRestrictionsMigrated =*/ true)); } void removeProfileOwner(int userId) { @@ -207,6 +218,38 @@ class Owners { return mDeviceOwner != null; } + /** + * @return true if user restrictions need to be migrated for DO. + */ + boolean getDeviceOwnerUserRestrictionsNeedsMigration() { + return mDeviceOwner != null && !mDeviceOwner.userRestrictionsMigrated; + } + + /** + * @return true if user restrictions need to be migrated for PO. + */ + boolean getProfileOwnerUserRestrictionsNeedsMigration(int userId) { + OwnerInfo profileOwner = mProfileOwners.get(userId); + return profileOwner != null && !profileOwner.userRestrictionsMigrated; + } + + /** Sets the user restrictions migrated flag, and also writes to the file. */ + void setDeviceOwnerUserRestrictionsMigrated() { + if (mDeviceOwner != null) { + mDeviceOwner.userRestrictionsMigrated = true; + } + writeDeviceOwner(); + } + + /** Sets the user restrictions migrated flag, and also writes to the file. */ + void setProfileOwnerUserRestrictionsMigrated(int userId) { + OwnerInfo profileOwner = mProfileOwners.get(userId); + if (profileOwner != null) { + profileOwner.userRestrictionsMigrated = true; + } + writeProfileOwner(userId); + } + private boolean readLegacyOwnerFile(File file) { if (!file.exists()) { // Already migrated or the device has no owners. @@ -226,7 +269,8 @@ class Owners { if (tag.equals(TAG_DEVICE_OWNER)) { String name = parser.getAttributeValue(null, ATTR_NAME); String packageName = parser.getAttributeValue(null, ATTR_PACKAGE); - mDeviceOwner = new OwnerInfo(name, packageName); + mDeviceOwner = new OwnerInfo(name, packageName, + /* userRestrictionsMigrated =*/ false); mDeviceOwnerUserId = UserHandle.USER_SYSTEM; } else if (tag.equals(TAG_DEVICE_INITIALIZER)) { // Deprecated tag @@ -241,7 +285,8 @@ class Owners { ComponentName admin = ComponentName.unflattenFromString( profileOwnerComponentStr); if (admin != null) { - profileOwnerInfo = new OwnerInfo(profileOwnerName, admin); + profileOwnerInfo = new OwnerInfo(profileOwnerName, admin, + /* userRestrictionsMigrated =*/ false); } else { // This shouldn't happen but switch from package name -> component name // might have written bad device owner files. b/17652534 @@ -250,7 +295,8 @@ class Owners { } } if (profileOwnerInfo == null) { - profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName); + profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName, + /* userRestrictionsMigrated =*/ false); } mProfileOwners.put(userId, profileOwnerInfo); } else if (TAG_SYSTEM_UPDATE_POLICY.equals(tag)) { @@ -503,21 +549,24 @@ class Owners { } } - private static class OwnerInfo { + static class OwnerInfo { public final String name; public final String packageName; public final ComponentName admin; + public boolean userRestrictionsMigrated; - public OwnerInfo(String name, String packageName) { + public OwnerInfo(String name, String packageName, boolean userRestrictionsMigrated) { this.name = name; this.packageName = packageName; this.admin = new ComponentName(packageName, ""); + this.userRestrictionsMigrated = userRestrictionsMigrated; } - public OwnerInfo(String name, ComponentName admin) { + public OwnerInfo(String name, ComponentName admin, boolean userRestrictionsMigrated) { this.name = name; this.admin = admin; this.packageName = admin.getPackageName(); + this.userRestrictionsMigrated = userRestrictionsMigrated; } public void writeToXml(XmlSerializer out, String tag) throws IOException { @@ -529,6 +578,8 @@ class Owners { if (admin != null) { out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString()); } + out.attribute(null, ATTR_USER_RESTRICTIONS_MIGRATED, + String.valueOf(userRestrictionsMigrated)); out.endTag(null, tag); } @@ -537,12 +588,16 @@ class Owners { final String name = parser.getAttributeValue(null, ATTR_NAME); final String componentName = parser.getAttributeValue(null, ATTR_COMPONENT_NAME); + final String userRestrictionsMigratedStr = + parser.getAttributeValue(null, ATTR_USER_RESTRICTIONS_MIGRATED); + final boolean userRestrictionsMigrated = + ("true".equals(userRestrictionsMigratedStr)); // Has component name? If so, return [name, component] if (componentName != null) { final ComponentName admin = ComponentName.unflattenFromString(componentName); if (admin != null) { - return new OwnerInfo(name, admin); + return new OwnerInfo(name, admin, userRestrictionsMigrated); } else { // This shouldn't happen but switch from package name -> component name // might have written bad device owner files. b/17652534 @@ -552,7 +607,7 @@ class Owners { } // Else, build with [name, package] - return new OwnerInfo(name, packageName); + return new OwnerInfo(name, packageName, userRestrictionsMigrated); } public void dump(String prefix, PrintWriter pw) { diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml new file mode 100644 index 0000000000000..9564969ab57cb --- /dev/null +++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml @@ -0,0 +1,4 @@ + + + + diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml new file mode 100644 index 0000000000000..48cb814fa907d --- /dev/null +++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml @@ -0,0 +1,7 @@ + + + + + + + diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml new file mode 100644 index 0000000000000..6b53840434c1e --- /dev/null +++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml new file mode 100644 index 0000000000000..2bcc5d41a7cb0 --- /dev/null +++ b/services/tests/servicestests/assets/DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java new file mode 100644 index 0000000000000..dfa9f8f383c5a --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceMigrationTest.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.server.devicepolicy; + +import com.android.server.LocalServices; +import com.android.server.SystemService; +import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable; + +import android.app.admin.DevicePolicyManager; +import android.app.admin.DevicePolicyManagerInternal; +import android.content.pm.PackageManager; +import android.content.pm.UserInfo; +import android.os.Bundle; +import android.os.UserHandle; +import android.os.UserManager; +import android.util.Pair; + +import org.mockito.invocation.InvocationOnMock; +import org.mockito.stubbing.Answer; + +import java.io.File; +import java.util.HashMap; +import java.util.Map; + +import static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyInt; +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doAnswer; +import static org.mockito.Mockito.when; + +public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase { + private DpmMockContext mContext; + + @Override + protected void setUp() throws Exception { + super.setUp(); + + mContext = getContext(); + + when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN))) + .thenReturn(true); + } + + public void testMigration() throws Exception { + final File user10dir = mMockContext.addUser(10, 0); + final File user11dir = mMockContext.addUser(11, UserInfo.FLAG_MANAGED_PROFILE); + final File user12dir = mMockContext.addUser(12, 0); + + setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); + setUpPackageManagerForAdmin(admin2, UserHandle.getUid(10, 123)); + setUpPackageManagerForAdmin(admin3, UserHandle.getUid(11, 456)); + + // Create the legacy owners & policies file. + DpmTestUtils.writeToFile( + (new File(mContext.dataDir, OwnersTestable.LEGACY_FILE)).getAbsoluteFile(), + DpmTestUtils.readAsset(mRealTestContext, + "DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml")); + + DpmTestUtils.writeToFile( + (new File(mContext.systemUserDataDir, "device_policies.xml")).getAbsoluteFile(), + DpmTestUtils.readAsset(mRealTestContext, + "DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml")); + + DpmTestUtils.writeToFile( + (new File(user10dir, "device_policies.xml")).getAbsoluteFile(), + DpmTestUtils.readAsset(mRealTestContext, + "DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml")); + DpmTestUtils.writeToFile( + (new File(user11dir, "device_policies.xml")).getAbsoluteFile(), + DpmTestUtils.readAsset(mRealTestContext, + "DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml")); + + // Set up UserManager + when(mMockContext.userManagerInternal.getBaseUserRestrictions( + eq(UserHandle.USER_SYSTEM))).thenReturn(DpmTestUtils.newRestrictions( + UserManager.DISALLOW_ADD_USER, + UserManager.DISALLOW_RECORD_AUDIO)); + + when(mMockContext.userManagerInternal.getBaseUserRestrictions( + eq(10))).thenReturn(DpmTestUtils.newRestrictions( + UserManager.DISALLOW_REMOVE_USER, + UserManager.DISALLOW_SMS, + UserManager.DISALLOW_OUTGOING_CALLS, + UserManager.DISALLOW_WALLPAPER, + UserManager.DISALLOW_RECORD_AUDIO)); + + when(mMockContext.userManagerInternal.getBaseUserRestrictions( + eq(11))).thenReturn(DpmTestUtils.newRestrictions( + UserManager.DISALLOW_REMOVE_USER, + UserManager.DISALLOW_SMS, + UserManager.DISALLOW_OUTGOING_CALLS, + UserManager.DISALLOW_WALLPAPER, + UserManager.DISALLOW_RECORD_AUDIO)); + + final Map newBaseRestrictions = new HashMap<>(); + + doAnswer(new Answer() { + @Override + public Void answer(InvocationOnMock invocation) throws Throwable { + Integer userId = (Integer) invocation.getArguments()[0]; + Bundle bundle = (Bundle) invocation.getArguments()[1]; + + newBaseRestrictions.put(userId, bundle); + + return null; + } + }).when(mContext.userManagerInternal).setBaseUserRestrictionsByDpmsForMigration( + anyInt(), any(Bundle.class)); + + // Initialize DPM/DPMS and let it migrate the persisted information. + // (Need clearCallingIdentity() to pass permission checks.) + + final DevicePolicyManagerServiceTestable dpms; + + final long ident = mContext.binder.clearCallingIdentity(); + try { + LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class); + + dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir); + + dpms.systemReady(SystemService.PHASE_LOCK_SETTINGS_READY); + dpms.systemReady(SystemService.PHASE_BOOT_COMPLETED); + } finally { + mContext.binder.restoreCallingIdentity(ident); + } + + // Now all information should be migrated. + assertFalse(dpms.mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(dpms.mOwners.getProfileOwnerUserRestrictionsNeedsMigration(12)); + + // Check the new base restrictions. + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_RECORD_AUDIO + ), + newBaseRestrictions.get(UserHandle.USER_SYSTEM)); + + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_SMS, + UserManager.DISALLOW_OUTGOING_CALLS, + UserManager.DISALLOW_RECORD_AUDIO + ), + newBaseRestrictions.get(10)); + + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_SMS, + UserManager.DISALLOW_OUTGOING_CALLS, + UserManager.DISALLOW_WALLPAPER, + UserManager.DISALLOW_RECORD_AUDIO + ), + newBaseRestrictions.get(11)); + + // Check the new owner restrictions. + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_ADD_USER + ), + dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()); + + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_REMOVE_USER, + UserManager.DISALLOW_WALLPAPER + ), + dpms.getProfileOwnerAdminLocked(10).ensureUserRestrictions()); + + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_REMOVE_USER + ), + dpms.getProfileOwnerAdminLocked(11).ensureUserRestrictions()); + } +} diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java index b109e7bc9d03a..2c01b8aaac12c 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java @@ -27,6 +27,7 @@ import android.os.Looper; import android.os.PowerManagerInternal; import android.os.UserHandle; import android.os.UserManager; +import android.os.UserManagerInternal; import android.view.IWindowManager; import java.io.File; @@ -106,6 +107,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi return context.userManager; } + @Override + UserManagerInternal getUserManagerInternal() { + return context.userManagerInternal; + } + @Override PowerManagerInternal getPowerManagerInternal() { return context.powerManagerInternal; @@ -153,7 +159,7 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi @Override String getDevicePolicyFilePathForSystemUser() { - return context.systemUserDataDir.getAbsolutePath(); + return context.systemUserDataDir.getAbsolutePath() + "/"; } @Override diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index d6a60c7f3e653..727858b77f41b 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -27,7 +27,6 @@ import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Intent; import android.content.pm.ApplicationInfo; -import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Bundle; @@ -70,9 +69,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { private DpmMockContext mContext; public DevicePolicyManager dpm; public DevicePolicyManagerServiceTestable dpms; - public ComponentName admin1; - public ComponentName admin2; - public ComponentName admin3; @Override protected void setUp() throws Exception { @@ -85,10 +81,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { initializeDpms(); - admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class); - admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class); - admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class); - setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID); setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID); setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID); @@ -113,67 +105,6 @@ public class DevicePolicyManagerTest extends DpmTestBase { } } - private void setUpPackageManagerForAdmin(ComponentName admin, int packageUid) throws Exception { - setUpPackageManagerForAdmin(admin, packageUid, - PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED); - } - - private void setUpPackageManagerForAdmin(ComponentName admin, int packageUid, - int enabledSetting) throws Exception { - - // Set up queryBroadcastReceivers(). - - final Intent resolveIntent = new Intent(); - resolveIntent.setComponent(admin); - final List realResolveInfo = - mRealTestContext.getPackageManager().queryBroadcastReceivers( - resolveIntent, - PackageManager.GET_META_DATA); - assertNotNull(realResolveInfo); - assertEquals(1, realResolveInfo.size()); - - // We need to change AI, so set a clone. - realResolveInfo.set(0, DpmTestUtils.cloneParcelable(realResolveInfo.get(0))); - - // We need to rewrite the UID in the activity info. - realResolveInfo.get(0).activityInfo.applicationInfo.uid = packageUid; - - doReturn(realResolveInfo).when(mContext.packageManager).queryBroadcastReceivers( - MockUtils.checkIntentComponent(admin), - eq(PackageManager.GET_META_DATA - | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), - eq(UserHandle.getUserId(packageUid))); - - // Set up getApplicationInfo(). - - final ApplicationInfo ai = DpmTestUtils.cloneParcelable( - mRealTestContext.getPackageManager().getApplicationInfo( - admin1.getPackageName(), - PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS)); - - ai.enabledSetting = enabledSetting; - ai.uid = packageUid; - - doReturn(ai).when(mContext.ipackageManager).getApplicationInfo( - eq(admin1.getPackageName()), - eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), - eq(UserHandle.getUserId(packageUid))); - - // Set up getPackageInfo(). - - final PackageInfo pi = DpmTestUtils.cloneParcelable( - mRealTestContext.getPackageManager().getPackageInfo( - admin1.getPackageName(), 0)); - assertTrue(pi.applicationInfo.flags != 0); - - pi.applicationInfo.uid = packageUid; - - doReturn(pi).when(mContext.ipackageManager).getPackageInfo( - eq(admin1.getPackageName()), - eq(0), - eq(UserHandle.getUserId(packageUid))); - } - private void setUpUserManager() { // Emulate UserManager.set/getApplicationRestriction(). final Map, Bundle> appRestrictions = new HashMap<>(); @@ -220,7 +151,7 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE)); // Check - assertEquals(admin1, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE)); + assertEquals(admin, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE)); } public void testHasNoFeature() throws Exception { @@ -743,6 +674,8 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertEquals("", dpms.getDeviceOwner().getClassName()); // Then create a new DPMS to have it load the settings from files. + when(mContext.userManager.getUserRestrictions(any(UserHandle.class))) + .thenReturn(new Bundle()); initializeDpms(); // Now the DO component name is a full name. @@ -802,32 +735,33 @@ public class DevicePolicyManagerTest extends DpmTestBase { assertTrue(dpm.setDeviceOwner(admin1, "owner-name", UserHandle.USER_SYSTEM)); - assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_SMS)); - assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions(), + dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() + ); dpm.addUserRestriction(admin1, UserManager.DISALLOW_SMS); dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS); - assertTrue(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_SMS)); - assertTrue(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_SMS, UserManager.DISALLOW_OUTGOING_CALLS), + dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() + ); dpm.clearUserRestriction(admin1, UserManager.DISALLOW_SMS); - assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_SMS)); - assertTrue(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS), + dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() + ); dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS); - assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_SMS)); - assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions(), + dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions() + ); // TODO Check inner calls. // TODO Make sure restrictions are written to the file. @@ -836,42 +770,106 @@ public class DevicePolicyManagerTest extends DpmTestBase { public void testSetUserRestriction_asPo() { setAsProfileOwner(admin1); - assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)); - assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions(), + dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) + .ensureUserRestrictions() + ); dpm.addUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS); - assertTrue(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)); - assertTrue(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES, + UserManager.DISALLOW_OUTGOING_CALLS + ), + dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) + .ensureUserRestrictions() + ); dpm.clearUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES); - assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)); - assertTrue(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions( + UserManager.DISALLOW_OUTGOING_CALLS + ), + dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) + .ensureUserRestrictions() + ); dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS); - assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES)); - assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) - .ensureUserRestrictions() - .getBoolean(UserManager.DISALLOW_OUTGOING_CALLS)); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions(), + dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE) + .ensureUserRestrictions() + ); // TODO Check inner calls. // TODO Make sure restrictions are written to the file. } + + public void testGetComposedUserRestrictions_noDoNoPo() throws Exception { + final Bundle in = DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS); + + Bundle actual = dpms.mLocalService.getComposedUserRestrictions( + UserHandle.USER_SYSTEM, in); + assertTrue(in == actual); + + actual = dpms.mLocalService.getComposedUserRestrictions( + DpmMockContext.CALLER_USER_HANDLE, in); + assertTrue(in == actual); + } + + public void testGetComposedUserRestrictions() throws Exception { + mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS); + mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS); + mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL); + + // First, set DO. + + // Call from a process on the system user. + mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID; + + // Make sure admin1 is installed on system user. + setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID); + + // Call. + dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM); + assertTrue(dpm.setDeviceOwner(admin1, "owner-name", + UserHandle.USER_SYSTEM)); + + dpm.addUserRestriction(admin1, "rest1"); + dpm.addUserRestriction(admin1, "rest2"); + + // Set PO on CALLER_USER_HANDLE. + mContext.binder.callingUid = DpmMockContext.CALLER_UID; + + setAsProfileOwner(admin2); + + dpm.addUserRestriction(admin2, "restA"); + dpm.addUserRestriction(admin2, "restB"); + + final Bundle in = DpmTestUtils.newRestrictions("abc"); + + Bundle actual = dpms.mLocalService.getComposedUserRestrictions( + UserHandle.USER_SYSTEM, in); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions("abc", "rest1", "rest2"), + actual); + + actual = dpms.mLocalService.getComposedUserRestrictions( + DpmMockContext.CALLER_USER_HANDLE, in); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions("abc", "rest1", "rest2", "restA", "restB"), + actual); + + actual = dpms.mLocalService.getComposedUserRestrictions( + DpmMockContext.CALLER_USER_HANDLE + 1, in); + DpmTestUtils.assertRestrictions( + DpmTestUtils.newRestrictions("abc", "rest1", "rest2"), + actual); + } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java index d1b483551809d..cc337b0a51317 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java @@ -36,6 +36,7 @@ import android.os.PowerManager.WakeLock; import android.os.PowerManagerInternal; import android.os.UserHandle; import android.os.UserManager; +import android.os.UserManagerInternal; import android.test.mock.MockContentResolver; import android.test.mock.MockContext; import android.view.IWindowManager; @@ -203,6 +204,7 @@ public class DpmMockContext extends MockContext { public final EnvironmentForMock environment; public final SystemPropertiesForMock systemProperties; public final UserManager userManager; + public final UserManagerInternal userManagerInternal; public final UserManagerForMock userManagerForMock; public final PowerManagerForMock powerManager; public final PowerManagerInternal powerManagerInternal; @@ -233,6 +235,7 @@ public class DpmMockContext extends MockContext { environment = mock(EnvironmentForMock.class); systemProperties= mock(SystemPropertiesForMock.class); userManager = mock(UserManager.class); + userManagerInternal = mock(UserManagerInternal.class); userManagerForMock = mock(UserManagerForMock.class); powerManager = mock(PowerManagerForMock.class); powerManagerInternal = mock(PowerManagerInternal.class); @@ -257,6 +260,9 @@ public class DpmMockContext extends MockContext { // System user is always running. setUserRunning(UserHandle.USER_SYSTEM, true); + + // This method must return an object. + when(userManagerInternal.getUserRestrictionsLock()).thenReturn(new Object()); } public File addUser(int userId, int flags) { diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java index 63bf12558dd14..e11f3fb0b6dae 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java @@ -16,10 +16,21 @@ package com.android.server.devicepolicy; +import android.content.ComponentName; import android.content.Context; +import android.content.Intent; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.content.pm.ResolveInfo; +import android.os.UserHandle; import android.test.AndroidTestCase; import java.io.File; +import java.util.List; + +import static org.mockito.Matchers.eq; +import static org.mockito.Mockito.doReturn; public abstract class DpmTestBase extends AndroidTestCase { public static final String TAG = "DpmTest"; @@ -29,6 +40,10 @@ public abstract class DpmTestBase extends AndroidTestCase { public File dataDir; + public ComponentName admin1; + public ComponentName admin2; + public ComponentName admin3; + @Override protected void setUp() throws Exception { super.setUp(); @@ -37,10 +52,77 @@ public abstract class DpmTestBase extends AndroidTestCase { mMockContext = new DpmMockContext( mRealTestContext, new File(mRealTestContext.getCacheDir(), "test-data")); + + admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class); + admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class); + admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class); } @Override public DpmMockContext getContext() { return mMockContext; } + + + protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid) + throws Exception { + setUpPackageManagerForAdmin(admin, packageUid, + PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED); + } + + protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid, + int enabledSetting) throws Exception { + + // Set up queryBroadcastReceivers(). + + final Intent resolveIntent = new Intent(); + resolveIntent.setComponent(admin); + final List realResolveInfo = + mRealTestContext.getPackageManager().queryBroadcastReceivers( + resolveIntent, + PackageManager.GET_META_DATA); + assertNotNull(realResolveInfo); + assertEquals(1, realResolveInfo.size()); + + // We need to change AI, so set a clone. + realResolveInfo.set(0, DpmTestUtils.cloneParcelable(realResolveInfo.get(0))); + + // We need to rewrite the UID in the activity info. + realResolveInfo.get(0).activityInfo.applicationInfo.uid = packageUid; + + doReturn(realResolveInfo).when(mMockContext.packageManager).queryBroadcastReceivers( + MockUtils.checkIntentComponent(admin), + eq(PackageManager.GET_META_DATA + | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), + eq(UserHandle.getUserId(packageUid))); + + // Set up getApplicationInfo(). + + final ApplicationInfo ai = DpmTestUtils.cloneParcelable( + mRealTestContext.getPackageManager().getApplicationInfo( + admin.getPackageName(), + PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS)); + + ai.enabledSetting = enabledSetting; + ai.uid = packageUid; + + doReturn(ai).when(mMockContext.ipackageManager).getApplicationInfo( + eq(admin.getPackageName()), + eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS), + eq(UserHandle.getUserId(packageUid))); + + // Set up getPackageInfo(). + + final PackageInfo pi = DpmTestUtils.cloneParcelable( + mRealTestContext.getPackageManager().getPackageInfo( + admin.getPackageName(), 0)); + assertTrue(pi.applicationInfo.flags != 0); + + pi.applicationInfo.uid = packageUid; + + doReturn(pi).when(mMockContext.ipackageManager).getPackageInfo( + eq(admin.getPackageName()), + eq(0), + eq(UserHandle.getUserId(packageUid))); + } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java index 7506273accb78..cceb2d2761fe4 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java @@ -16,21 +16,35 @@ package com.android.server.devicepolicy; +import com.google.android.collect.Lists; +import com.google.android.collect.Sets; + +import android.content.Context; +import android.os.Bundle; import android.os.FileUtils; import android.os.Parcel; import android.os.Parcelable; +import android.test.AndroidTestCase; import android.util.Log; import android.util.Printer; import org.junit.Assert; +import java.io.BufferedReader; import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.Set; -public class DpmTestUtils { - private DpmTestUtils() { - } +import junit.framework.AssertionFailedError; +public class DpmTestUtils extends AndroidTestCase { public static void clearDir(File dir) { if (dir.exists()) { Assert.assertTrue("failed to delete dir", FileUtils.deleteContents(dir)); @@ -43,6 +57,44 @@ public class DpmTestUtils { return list == null ? 0 : list.size(); } + public static Bundle newRestrictions(String... restrictions) { + final Bundle ret = new Bundle(); + for (String restriction : restrictions) { + ret.putBoolean(restriction, true); + } + return ret; + } + + public static void assertRestrictions(Bundle expected, Bundle actual) { + final ArrayList elist; + if (expected == null) { + elist = null; + } else { + elist = Lists.newArrayList(); + for (String key : expected.keySet()) { + if (expected.getBoolean(key)) { + elist.add(key); + } + } + Collections.sort(elist); + } + + final ArrayList alist; + if (actual == null) { + alist = null; + } else { + alist = Lists.newArrayList(); + for (String key : actual.keySet()) { + if (actual.getBoolean(key)) { + alist.add(key); + } + } + Collections.sort(alist); + } + + assertEquals(elist, alist); + } + public static T cloneParcelable(T source) { Parcel p = Parcel.obtain(); p.writeParcelable(source, 0); @@ -58,4 +110,57 @@ public class DpmTestUtils { Log.i(DpmTestBase.TAG, x); } }; + + public static String readAsset(Context context, String assetPath) throws IOException { + final StringBuilder sb = new StringBuilder(); + try (BufferedReader br = new BufferedReader( + new InputStreamReader( + context.getResources().getAssets().open(assetPath)))) { + String line; + while ((line = br.readLine()) != null) { + sb.append(line); + sb.append(System.lineSeparator()); + } + } + return sb.toString(); + } + + public static void writeToFile(File path, String content) + throws IOException { + path.getParentFile().mkdirs(); + + try (FileWriter writer = new FileWriter(path)) { + Log.i(DpmTestBase.TAG, "Writing to " + path); + Log.i(DpmTestBase.TAG, content); + writer.write(content); + } + } + + private static boolean checkAssertRestrictions(Bundle a, Bundle b) { + try { + assertRestrictions(a, b); + return true; + } catch (AssertionFailedError e) { + return false; + } + } + + public void testAssertRestrictions() { + final Bundle a = newRestrictions(); + final Bundle b = newRestrictions("a"); + final Bundle c = newRestrictions("a"); + final Bundle d = newRestrictions("b", "c"); + final Bundle e = newRestrictions("b", "c"); + + assertTrue(checkAssertRestrictions(null, null)); + assertFalse(checkAssertRestrictions(null, a)); + assertFalse(checkAssertRestrictions(a, null)); + assertTrue(checkAssertRestrictions(a, a)); + + assertFalse(checkAssertRestrictions(a, b)); + assertTrue(checkAssertRestrictions(b, c)); + + assertFalse(checkAssertRestrictions(c, d)); + assertTrue(checkAssertRestrictions(d, e)); + } } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java index 79845d21281ff..4e1176233c9f7 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/OwnersTest.java @@ -47,31 +47,6 @@ import static org.mockito.Mockito.when; (mmma frameworks/base/services/tests/servicestests/ for non-ninja build) */ public class OwnersTest extends DpmTestBase { - private String readAsset(String assetPath) throws IOException { - final StringBuilder sb = new StringBuilder(); - try (BufferedReader br = new BufferedReader( - new InputStreamReader( - mRealTestContext.getResources().getAssets().open(assetPath)))) { - String line; - while ((line = br.readLine()) != null) { - sb.append(line); - sb.append(System.lineSeparator()); - } - } - return sb.toString(); - } - - private void createLegacyFile(File path, String content) - throws IOException { - path.getParentFile().mkdirs(); - - try (FileWriter writer = new FileWriter(path)) { - Log.i(TAG, "Writing to " + path); - Log.i(TAG, content); - writer.write(content); - } - } - public void testUpgrade01() throws Exception { getContext().addUsers(10, 11, 20, 21); @@ -79,8 +54,8 @@ public class OwnersTest extends DpmTestBase { { final OwnersTestable owners = new OwnersTestable(getContext()); - createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), - readAsset("OwnersTest/test01/input.xml")); + DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(), + DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test01/input.xml")); owners.load(); @@ -99,6 +74,12 @@ public class OwnersTest extends DpmTestBase { assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId()); assertNull(owners.getSystemUpdatePolicy()); assertEquals(0, owners.getProfileOwnerKeys().size()); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } // Then re-read and check. @@ -110,6 +91,12 @@ public class OwnersTest extends DpmTestBase { assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId()); assertNull(owners.getSystemUpdatePolicy()); assertEquals(0, owners.getProfileOwnerKeys().size()); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } } @@ -120,8 +107,8 @@ public class OwnersTest extends DpmTestBase { { final OwnersTestable owners = new OwnersTestable(getContext()); - createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), - readAsset("OwnersTest/test02/input.xml")); + DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(), + DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test02/input.xml")); owners.load(); @@ -142,6 +129,12 @@ public class OwnersTest extends DpmTestBase { assertNull(owners.getSystemUpdatePolicy()); assertEquals(0, owners.getProfileOwnerKeys().size()); + + assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } // Then re-read and check. @@ -156,6 +149,12 @@ public class OwnersTest extends DpmTestBase { assertNull(owners.getSystemUpdatePolicy()); assertEquals(0, owners.getProfileOwnerKeys().size()); + + assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } } @@ -166,8 +165,8 @@ public class OwnersTest extends DpmTestBase { { final OwnersTestable owners = new OwnersTestable(getContext()); - createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), - readAsset("OwnersTest/test03/input.xml")); + DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(), + DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test03/input.xml")); owners.load(); @@ -196,6 +195,12 @@ public class OwnersTest extends DpmTestBase { owners.getProfileOwnerComponent(11)); assertEquals("1", owners.getProfileOwnerName(11)); assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11)); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } // Then re-read and check. @@ -218,9 +223,19 @@ public class OwnersTest extends DpmTestBase { owners.getProfileOwnerComponent(11)); assertEquals("1", owners.getProfileOwnerName(11)); assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11)); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } } + /** + * Note this also tests {@link Owners#setDeviceOwnerUserRestrictionsMigrated()} + * and {@link Owners#setProfileOwnerUserRestrictionsMigrated(int)}. + */ public void testUpgrade04() throws Exception { getContext().addUsers(10, 11, 20, 21); @@ -228,8 +243,8 @@ public class OwnersTest extends DpmTestBase { { final OwnersTestable owners = new OwnersTestable(getContext()); - createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), - readAsset("OwnersTest/test04/input.xml")); + DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(), + DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test04/input.xml")); owners.load(); @@ -262,6 +277,12 @@ public class OwnersTest extends DpmTestBase { owners.getProfileOwnerComponent(11)); assertEquals("1", owners.getProfileOwnerName(11)); assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11)); + + assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } // Then re-read and check. @@ -288,6 +309,40 @@ public class OwnersTest extends DpmTestBase { owners.getProfileOwnerComponent(11)); assertEquals("1", owners.getProfileOwnerName(11)); assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11)); + + assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + + owners.setDeviceOwnerUserRestrictionsMigrated(); + } + + { + final OwnersTestable owners = new OwnersTestable(getContext()); + owners.load(); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + + owners.setProfileOwnerUserRestrictionsMigrated(11); + } + + { + final OwnersTestable owners = new OwnersTestable(getContext()); + owners.load(); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); + + owners.setProfileOwnerUserRestrictionsMigrated(11); } } @@ -298,8 +353,8 @@ public class OwnersTest extends DpmTestBase { { final OwnersTestable owners = new OwnersTestable(getContext()); - createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), - readAsset("OwnersTest/test05/input.xml")); + DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(), + DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test05/input.xml")); owners.load(); @@ -319,6 +374,12 @@ public class OwnersTest extends DpmTestBase { assertNull(owners.getSystemUpdatePolicy()); assertEquals(0, owners.getProfileOwnerKeys().size()); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } // Then re-read and check. @@ -332,6 +393,12 @@ public class OwnersTest extends DpmTestBase { assertNull(owners.getSystemUpdatePolicy()); assertEquals(0, owners.getProfileOwnerKeys().size()); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } } @@ -342,8 +409,8 @@ public class OwnersTest extends DpmTestBase { { final OwnersTestable owners = new OwnersTestable(getContext()); - createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), - readAsset("OwnersTest/test06/input.xml")); + DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(), + DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test06/input.xml")); owners.load(); @@ -362,6 +429,12 @@ public class OwnersTest extends DpmTestBase { assertNotNull(owners.getSystemUpdatePolicy()); assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType()); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } // Then re-read and check. @@ -375,6 +448,12 @@ public class OwnersTest extends DpmTestBase { assertNotNull(owners.getSystemUpdatePolicy()); assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType()); + + assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration()); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20)); + assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21)); } } @@ -384,8 +463,8 @@ public class OwnersTest extends DpmTestBase { final OwnersTestable owners = new OwnersTestable(getContext()); // First, migrate to create new-style config files. - createLegacyFile(owners.getLegacyConfigFileWithTestOverride(), - readAsset("OwnersTest/test04/input.xml")); + DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(), + DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test04/input.xml")); owners.load(); diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java index 86f5ed7346cb6..66c7dbb16edec 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java @@ -211,11 +211,14 @@ public class UserManagerTest extends AndroidTestCase { public void testRestrictions() { UserInfo testUser = createUser("User 1", 0); - Bundle restrictions = new Bundle(); - restrictions.putBoolean(UserManager.DISALLOW_INSTALL_APPS, true); - restrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, false); - mUserManager.setUserRestrictions(restrictions, new UserHandle(testUser.id)); + + mUserManager.setUserRestriction( + UserManager.DISALLOW_INSTALL_APPS, true, new UserHandle(testUser.id)); + mUserManager.setUserRestriction( + UserManager.DISALLOW_CONFIG_WIFI, false, new UserHandle(testUser.id)); + Bundle stored = mUserManager.getUserRestrictions(new UserHandle(testUser.id)); + // Note this will fail if DO already sets those restrictions. assertEquals(stored.getBoolean(UserManager.DISALLOW_CONFIG_WIFI), false); assertEquals(stored.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS), false); assertEquals(stored.getBoolean(UserManager.DISALLOW_INSTALL_APPS), true);