package android.app.admin;
+import android.os.Bundle;
+
import java.util.List;
/**
* @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);
}
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);
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;
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
*
* <p/>Key for user restrictions.
* <p/>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";
* 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";
*
* <p/>Key for user restrictions.
* <p/>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";
* Specifies if a user is not allowed to record audio. This restriction is always enabled for
* background users. The default value is <code>false</code>.
*
- * @see #setUserRestrictions(Bundle)
+ * @see DevicePolicyManager#addUserRestriction(ComponentName, String)
+ * @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
* @see #getUserRestrictions()
* @hide
*/
*
* <p/>Key for user restrictions.
* <p/>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
}
/**
- * 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");
}
/**
*/
@Deprecated
public void setUserRestriction(String key, boolean value) {
- Bundle bundle = getUserRestrictions();
- bundle.putBoolean(key, value);
- setUserRestrictions(bundle);
+ setUserRestriction(key, value, Process.myUserHandle());
}
/**
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);
* @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.
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.
--- /dev/null
+/*
+ * 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);
+}
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;
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;
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;
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";
private final File mUserListFile;
private final SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
- private final SparseArray<Bundle> mUserRestrictions = new SparseArray<Bundle>();
+
+ 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<Bundle> 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<Bundle> mCachedEffectiveUserRestrictions = new SparseArray<>();
+
private final Bundle mGuestRestrictions = new Bundle();
/**
private IAppOpsService mAppOpsService;
+ private final LocalService mLocalService;
+
private static UserManagerService sInstance;
public static UserManagerService getInstance() {
sInstance = this;
}
}
+ mLocalService = new LocalService();
+ LocalServices.addService(UserManagerInternal.class, mLocalService);
}
void systemReady() {
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");
}
}
}
+ @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) {
- synchronized (mPackagesLock) {
- Bundle restrictions = mUserRestrictions.get(userId);
- return restrictions != null && restrictions.getBoolean(restrictionKey);
- }
+ 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;
+ /**
+ * 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);
- 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);
+ // 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);
}
/**
mUserVersion = USER_VERSION;
Bundle restrictions = new Bundle();
- mUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions);
+ synchronized (mRestrictionsLock) {
+ mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions);
+ }
updateUserIdsLocked();
initDefaultGuestRestrictions();
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);
userInfo.guestToRemove = guestToRemove;
userInfo.profileGroupId = profileGroupId;
userInfo.restrictedProfileParentId = restrictedProfileParentId;
- mUserRestrictions.append(id, restrictions);
+ synchronized (mRestrictionsLock) {
+ mBaseUserRestrictions.append(id, restrictions);
+ }
return userInfo;
} catch (IOException ioe) {
scheduleWriteUserLocked(userInfo);
updateUserIdsLocked();
Bundle restrictions = new Bundle();
- mUserRestrictions.append(userId, restrictions);
+ synchronized (mRestrictionsLock) {
+ mBaseUserRestrictions.append(userId, restrictions);
+ }
}
}
mPm.newUserCreated(userId);
}
}
- @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
}
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:");
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);
+ }
+ }
+ }
+ }
}
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");
}
}
+ 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) {
noneSet = false;
}
}
- }
- if (noneSet) {
- pw.println(prefix + "none");
+ if (noneSet) {
+ pw.println(prefix + "none");
+ }
+ } else {
+ pw.println(prefix + "null");
}
}
}
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;
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;
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";
final Injector mInjector;
final IPackageManager mIPackageManager;
final UserManager mUserManager;
+ final UserManagerInternal mUserManagerInternal;
final LocalService mLocalService;
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() {
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--) {
return UserManager.get(mContext);
}
+ UserManagerInternal getUserManagerInternal() {
+ return LocalServices.getService(UserManagerInternal.class);
+ }
+
NotificationManager getNotificationManager() {
return mContext.getSystemService(NotificationManager.class);
}
mOwners = Preconditions.checkNotNull(injector.newOwners());
mUserManager = Preconditions.checkNotNull(injector.getUserManager());
+ mUserManagerInternal = Preconditions.checkNotNull(injector.getUserManagerInternal());
mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
mLocalService = new LocalService();
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 (?)
}
}
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<String> normalExceptionList = Sets.newArraySet(
+ UserManager.DISALLOW_OUTGOING_CALLS,
+ UserManager.DISALLOW_SMS);
+ normalExceptionList.addAll(UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS);
+
+ final Set<String> 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<String> 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<String> 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) {
nFound++;
}
}
- if (nFound > 0) {
+ if (nFound > 1) {
Slog.w(LOG_TAG, "Multiple DA found; assume the first one is DO.");
}
return found;
? 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"));
}
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 "
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);
}
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);
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());
}
@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));
-
- 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_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);
+ }
}
- }
- 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);
}
}
long id = mInjector.binderClearCallingIdentity();
try {
- if (DBG) {
+ if (VERBOSE_LOG) {
Slog.v(LOG_TAG, "installing " + packageName + " for "
+ userId);
}
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) {
}
}
- private final class LocalService extends DevicePolicyManagerInternal {
+ @VisibleForTesting
+ final class LocalService extends DevicePolicyManagerInternal {
private List<OnCrossProfileWidgetProvidersChangeListener> mWidgetProviderListeners;
@Override
}
}
+ @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<String> packages) {
final List<OnCrossProfileWidgetProvidersChangeListener> listeners;
synchronized (DevicePolicyManagerService.this) {
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;
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";
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;
}
}
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) {
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.
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
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
}
}
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)) {
}
}
- 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 {
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);
}
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
}
// Else, build with [name, package]
- return new OwnerInfo(name, packageName);
+ return new OwnerInfo(name, packageName, userRestrictionsMigrated);
}
public void dump(String prefix, PrintWriter pw) {
--- /dev/null
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<device-owner package="com.android.frameworks.servicestests" />
+<profile-owner package="com.android.frameworks.servicestests" name="0" userId="10" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin2" />
+<profile-owner package="com.android.frameworks.servicestests" name="0" userId="11" component="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin3" />
--- /dev/null
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policies setup-complete="true">
+ <admin name="com.google.android.gms/com.google.android.gms.mdm.receivers.MdmDeviceAdminReceiver">
+ </admin>
+ <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin1">
+ </admin>
+</policies>
--- /dev/null
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policies setup-complete="true">
+ <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin2">
+ </admin>
+</policies>
--- /dev/null
+<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
+<policies setup-complete="true">
+ <admin name="com.android.frameworks.servicestests/com.android.server.devicepolicy.DummyDeviceAdmins$Admin3">
+ </admin>
+</policies>
--- /dev/null
+/*
+ * 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<Integer, Bundle> newBaseRestrictions = new HashMap<>();
+
+ doAnswer(new Answer<Void>() {
+ @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());
+ }
+}
import android.os.PowerManagerInternal;
import android.os.UserHandle;
import android.os.UserManager;
+import android.os.UserManagerInternal;
import android.view.IWindowManager;
import java.io.File;
}
@Override
+ UserManagerInternal getUserManagerInternal() {
+ return context.userManagerInternal;
+ }
+
+ @Override
PowerManagerInternal getPowerManagerInternal() {
return context.powerManagerInternal;
}
@Override
String getDevicePolicyFilePathForSystemUser() {
- return context.systemUserDataDir.getAbsolutePath();
+ return context.systemUserDataDir.getAbsolutePath() + "/";
}
@Override
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;
private DpmMockContext mContext;
public DevicePolicyManager dpm;
public DevicePolicyManagerServiceTestable dpms;
- public ComponentName admin1;
- public ComponentName admin2;
- public ComponentName admin3;
@Override
protected void setUp() throws Exception {
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);
}
}
- 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<ResolveInfo> 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<Pair<String, UserHandle>, Bundle> appRestrictions = new HashMap<>();
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 {
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.
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.
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);
+ }
}
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;
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;
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);
// 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) {
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";
public File dataDir;
+ public ComponentName admin1;
+ public ComponentName admin2;
+ public ComponentName admin3;
+
@Override
protected void setUp() throws Exception {
super.setUp();
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<ResolveInfo> 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)));
+ }
}
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));
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<String> 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<String> 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 extends Parcelable> T cloneParcelable(T source) {
Parcel p = Parcel.obtain();
p.writeParcelable(source, 0);
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));
+ }
}
(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);
{
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();
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.
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));
}
}
{
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();
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.
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));
}
}
{
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();
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.
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);
{
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();
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.
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);
}
}
{
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();
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.
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));
}
}
{
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();
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.
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));
}
}
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();
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);