Layer user restrictions

- Now DPMS remembers user restrictions set by DO / PO in their ActiveAdmin.

- User restrictions set by DO/PO will no longer be saved by UserManger.  Instead,
when needed, UMS will consult DPMS to build "effective" user restrictions.

- UM.getUserRestrictions() will now always return "effective" user restrictions.

- DPMS migrates existing user restrictions per the eng spec.

- Also now UM.setUserRestrictions() will crash.  UMS.setUserRestrictions() has
been removed.
This was needed because UM.setUserRestrctions(UM.getUserRestrictions()) will no
longer be a valid use like it used to be.

- Also introduced a fined-grained lock for user restrictions in UM to avoid
deadlock between DPMS and also for better performance.

Bug 23902097

Change-Id: If0e1e49344e2f3e9226532d00777976d1eaa7df3
This commit is contained in:
Makoto Onuki
2015-10-13 14:34:03 -07:00
parent 7fef1888d1
commit 068c54a5be
20 changed files with 1410 additions and 443 deletions

View File

@@ -16,6 +16,8 @@
package android.app.admin;
import android.os.Bundle;
import java.util.List;
/**
@@ -69,4 +71,13 @@ public abstract class DevicePolicyManagerInternal {
* @return true if the uid is an active admin with the given policy.
*/
public abstract boolean isActiveAdminWithPolicy(int uid, int reqPolicy);
/**
* Takes a {@link Bundle} containing "base" user restrictions stored in
* {@link com.android.server.pm.UserManagerService}, mixes restrictions set by the device owner
* and the profile owner and returns the merged restrictions.
*
* This method always returns a new {@link Bundle}.
*/
public abstract Bundle getComposedUserRestrictions(int userId, Bundle inBundle);
}

View File

@@ -55,14 +55,12 @@ interface IUserManager {
int getUserHandle(int userSerialNumber);
Bundle getUserRestrictions(int userHandle);
boolean hasUserRestriction(in String restrictionKey, int userHandle);
void setUserRestrictions(in Bundle restrictions, int userHandle);
void setUserRestriction(String key, boolean value, int userId);
void setSystemControlledUserRestriction(String key, boolean value, int userId);
void setApplicationRestrictions(in String packageName, in Bundle restrictions,
int userHandle);
Bundle getApplicationRestrictions(in String packageName);
Bundle getApplicationRestrictionsForUser(in String packageName, int userHandle);
void removeRestrictions();
void setDefaultGuestRestrictions(in Bundle restrictions);
Bundle getDefaultGuestRestrictions();
boolean markGuestForDeletion(int userHandle);

View File

@@ -21,6 +21,7 @@ import android.annotation.SystemApi;
import android.app.ActivityManager;
import android.app.ActivityManagerNative;
import android.app.admin.DevicePolicyManager;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.UserInfo;
import android.content.res.Resources;
@@ -55,7 +56,8 @@ public class UserManager {
*
* <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";
@@ -67,7 +69,8 @@ public class UserManager {
*
* <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";
@@ -78,7 +81,8 @@ public class UserManager {
*
* <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";
@@ -89,7 +93,8 @@ public class UserManager {
*
* <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";
@@ -102,7 +107,8 @@ public class UserManager {
*
* <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";
@@ -114,7 +120,8 @@ public class UserManager {
*
* <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";
@@ -127,7 +134,8 @@ public class UserManager {
*
* <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";
@@ -139,7 +147,8 @@ public class UserManager {
*
* <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";
@@ -150,7 +159,8 @@ public class UserManager {
*
* <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";
@@ -163,7 +173,8 @@ public class UserManager {
*
* <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";
@@ -174,7 +185,8 @@ public class UserManager {
*
* <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";
@@ -187,7 +199,8 @@ public class UserManager {
*
* <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";
@@ -199,7 +212,8 @@ public class UserManager {
*
* <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";
@@ -213,7 +227,8 @@ public class UserManager {
*
* <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";
@@ -227,7 +242,8 @@ public class UserManager {
*
* <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";
@@ -241,7 +257,8 @@ public class UserManager {
*
* <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";
@@ -252,7 +269,8 @@ public class UserManager {
*
* <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";
@@ -266,7 +284,8 @@ public class UserManager {
*
* <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";
@@ -280,7 +299,8 @@ public class UserManager {
*
* <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";
@@ -300,7 +320,8 @@ public class UserManager {
*
* <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";
@@ -312,7 +333,8 @@ public class UserManager {
*
* <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";
@@ -324,7 +346,8 @@ public class UserManager {
*
* <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";
@@ -336,7 +359,8 @@ public class UserManager {
*
* <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";
@@ -350,7 +374,8 @@ public class UserManager {
*
* <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";
@@ -361,7 +386,8 @@ public class UserManager {
*
* <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";
@@ -373,7 +399,8 @@ public class UserManager {
*
* <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";
@@ -393,7 +420,8 @@ public class UserManager {
*
* <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";
@@ -406,7 +434,8 @@ public class UserManager {
*
* <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";
@@ -417,7 +446,8 @@ public class UserManager {
*
* <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";
@@ -426,7 +456,8 @@ public class UserManager {
* Hidden user restriction to disallow access to wallpaper manager APIs. This user restriction
* is always set for managed profiles.
* @hide
* @see #setUserRestrictions(Bundle)
* @see DevicePolicyManager#addUserRestriction(ComponentName, String)
* @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
* @see #getUserRestrictions()
*/
public static final String DISALLOW_WALLPAPER = "no_wallpaper";
@@ -438,7 +469,8 @@ public class UserManager {
*
* <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";
@@ -447,7 +479,8 @@ public class UserManager {
* Specifies if a user is not allowed to record audio. This restriction is always enabled for
* background users. The default value is <code>false</code>.
*
* @see #setUserRestrictions(Bundle)
* @see DevicePolicyManager#addUserRestriction(ComponentName, String)
* @see DevicePolicyManager#clearUserRestriction(ComponentName, String)
* @see #getUserRestrictions()
* @hide
*/
@@ -466,7 +499,8 @@ public class UserManager {
*
* <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
@@ -740,36 +774,20 @@ public class UserManager {
}
/**
* Sets all the user-wide restrictions for this user.
* Requires the MANAGE_USERS permission.
* @param restrictions the Bundle containing all the restrictions.
* @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction(
* android.content.ComponentName, String)} or
* {@link android.app.admin.DevicePolicyManager#clearUserRestriction(
* android.content.ComponentName, String)} instead.
* This will no longer work. Use {@link #setUserRestriction(String, boolean)} instead.
*/
@Deprecated
public void setUserRestrictions(Bundle restrictions) {
setUserRestrictions(restrictions, Process.myUserHandle());
throw new UnsupportedOperationException("This method is no longer supported");
}
/**
* Sets all the user-wide restrictions for the specified user.
* Requires the MANAGE_USERS permission.
* @param restrictions the Bundle containing all the restrictions.
* @param userHandle the UserHandle of the user for whom to set the restrictions.
* @deprecated use {@link android.app.admin.DevicePolicyManager#addUserRestriction(
* android.content.ComponentName, String)} or
* {@link android.app.admin.DevicePolicyManager#clearUserRestriction(
* android.content.ComponentName, String)} instead.
* This will no longer work. Use {@link #setUserRestriction(String, boolean, UserHandle)}
* instead.
*/
@Deprecated
public void setUserRestrictions(Bundle restrictions, UserHandle userHandle) {
try {
mService.setUserRestrictions(restrictions, userHandle.getIdentifier());
} catch (RemoteException re) {
Log.w(TAG, "Could not set user restrictions", re);
}
throw new UnsupportedOperationException("This method is no longer supported");
}
/**
@@ -784,9 +802,7 @@ public class UserManager {
*/
@Deprecated
public void setUserRestriction(String key, boolean value) {
Bundle bundle = getUserRestrictions();
bundle.putBoolean(key, value);
setUserRestrictions(bundle);
setUserRestriction(key, value, Process.myUserHandle());
}
/**
@@ -882,9 +898,8 @@ public class UserManager {
try {
user = mService.createUser(name, flags);
if (user != null && !user.isAdmin()) {
Bundle userRestrictions = mService.getUserRestrictions(user.id);
addDefaultUserRestrictions(userRestrictions);
mService.setUserRestrictions(userRestrictions, user.id);
mService.setUserRestriction(DISALLOW_SMS, true, user.id);
mService.setUserRestriction(DISALLOW_OUTGOING_CALLS, true, user.id);
}
} catch (RemoteException re) {
Log.w(TAG, "Could not create a user", re);
@@ -899,27 +914,22 @@ public class UserManager {
* @hide
*/
public UserInfo createGuest(Context context, String name) {
UserInfo guest = createUser(name, UserInfo.FLAG_GUEST);
if (guest != null) {
Settings.Secure.putStringForUser(context.getContentResolver(),
Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
try {
Bundle guestRestrictions = mService.getDefaultGuestRestrictions();
guestRestrictions.putBoolean(DISALLOW_SMS, true);
guestRestrictions.putBoolean(DISALLOW_INSTALL_UNKNOWN_SOURCES, true);
mService.setUserRestrictions(guestRestrictions, guest.id);
} catch (RemoteException re) {
Log.w(TAG, "Could not update guest restrictions");
UserInfo guest = null;
try {
guest = mService.createUser(name, UserInfo.FLAG_GUEST);
if (guest != null) {
Settings.Secure.putStringForUser(context.getContentResolver(),
Settings.Secure.SKIP_FIRST_USE_HINTS, "1", guest.id);
mService.setUserRestriction(DISALLOW_SMS, true, guest.id);
mService.setUserRestriction(DISALLOW_INSTALL_UNKNOWN_SOURCES, true, guest.id);
}
} catch (RemoteException re) {
Log.w(TAG, "Could not create a user", re);
}
return guest;
}
private static void addDefaultUserRestrictions(Bundle restrictions) {
restrictions.putBoolean(DISALLOW_OUTGOING_CALLS, true);
restrictions.putBoolean(DISALLOW_SMS, true);
}
/**
* Creates a user with the specified name and options as a profile of another user.
* Requires {@link android.Manifest.permission#MANAGE_USERS} permission.
@@ -1465,15 +1475,6 @@ public class UserManager {
return false;
}
/** @hide */
public void removeRestrictions() {
try {
mService.removeRestrictions();
} catch (RemoteException re) {
Log.w(TAG, "Could not change restrictions pin");
}
}
/**
* @hide
* Set restrictions that should apply to any future guest user that's created.

View File

@@ -0,0 +1,63 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.os;
/**
* @hide Only for use within the system server.
*/
public abstract class UserManagerInternal {
/**
* Lock that must be held when calling certain methods in this class.
*
* This is used to avoid dead lock between
* {@link com.android.server.pm.UserManagerService} and
* {@link com.android.server.devicepolicy.DevicePolicyManagerService}. This lock should not
* be newly taken while holding the DPMS lock, which would cause a dead lock. Take this
* lock first before taking the DPMS lock to avoid that.
*/
public abstract Object getUserRestrictionsLock();
/**
* Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to get
* {@link com.android.server.pm.UserManagerService} to update effective user restrictions.
*
* Must be called while taking the {@link #getUserRestrictionsLock()} lock.
*/
public abstract void updateEffectiveUserRestrictionsRL(int userId);
/**
* Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} to get
* {@link com.android.server.pm.UserManagerService} to update effective user restrictions.
*
* Must be called while taking the {@link #getUserRestrictionsLock()} lock.
*/
public abstract void updateEffectiveUserRestrictionsForAllUsersRL();
/**
* Returns the "base" user restrictions.
*
* Used by {@link com.android.server.devicepolicy.DevicePolicyManagerService} for upgrading
* from MNC.
*/
public abstract Bundle getBaseUserRestrictions(int userId);
/**
* Called by {@link com.android.server.devicepolicy.DevicePolicyManagerService} for upgrading
* from MNC.
*/
public abstract void setBaseUserRestrictionsByDpmsForMigration(int userId,
Bundle baseRestrictions);
}

View File

@@ -16,14 +16,15 @@
package com.android.server.pm;
import android.accounts.Account;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManagerInternal;
import android.app.ActivityManagerNative;
import android.app.IStopUserCallback;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
@@ -46,6 +47,7 @@ import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.os.storage.StorageManager;
import android.os.storage.VolumeInfo;
import android.system.ErrnoException;
@@ -59,9 +61,11 @@ import android.util.SparseBooleanArray;
import android.util.TimeUtils;
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IAppOpsService;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
import com.android.server.LocalServices;
@@ -83,11 +87,18 @@ import java.util.List;
import libcore.io.IoUtils;
/**
* Service for {@link UserManager}.
*
* Method naming convention:
* - Methods suffixed with "Locked" should be called within the {@code this} lock.
* - Methods suffixed with "RL" should be called within the {@link #mRestrictionsLock} lock.
*/
public class UserManagerService extends IUserManager.Stub {
private static final String LOG_TAG = "UserManagerService";
private static final boolean DBG = false;
private static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
private static final String TAG_NAME = "name";
private static final String ATTR_FLAGS = "flags";
@@ -160,7 +171,38 @@ public class UserManagerService extends IUserManager.Stub {
private final File mUserListFile;
private final SparseArray<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();
/**
@@ -176,6 +218,8 @@ public class UserManagerService extends IUserManager.Stub {
private IAppOpsService mAppOpsService;
private final LocalService mLocalService;
private static UserManagerService sInstance;
public static UserManagerService getInstance() {
@@ -231,6 +275,8 @@ public class UserManagerService extends IUserManager.Stub {
sInstance = this;
}
}
mLocalService = new LocalService();
LocalServices.addService(UserManagerInternal.class, mLocalService);
}
void systemReady() {
@@ -258,8 +304,9 @@ public class UserManagerService extends IUserManager.Stub {
mAppOpsService = IAppOpsService.Stub.asInterface(
ServiceManager.getService(Context.APP_OPS_SERVICE));
for (int i = 0; i < mUserIds.length; ++i) {
final int userId = mUserIds[i];
try {
mAppOpsService.setUserRestrictions(mUserRestrictions.get(mUserIds[i]), mUserIds[i]);
mAppOpsService.setUserRestrictions(getEffectiveUserRestrictions(userId), userId);
} catch (RemoteException e) {
Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
}
@@ -588,75 +635,171 @@ public class UserManagerService extends IUserManager.Stub {
}
}
@Override
public boolean hasUserRestriction(String restrictionKey, int userId) {
synchronized (mPackagesLock) {
Bundle restrictions = mUserRestrictions.get(userId);
return restrictions != null && restrictions.getBoolean(restrictionKey);
@GuardedBy("mRestrictionsLock")
private Bundle computeEffectiveUserRestrictionsRL(int userId) {
final DevicePolicyManagerInternal dpmi =
LocalServices.getService(DevicePolicyManagerInternal.class);
final Bundle systemRestrictions = mBaseUserRestrictions.get(userId);
final Bundle effective;
if (dpmi == null) {
// TODO Make sure it's because DPMS is disabled and not because we called it too early.
effective = systemRestrictions;
} else {
effective = dpmi.getComposedUserRestrictions(userId, systemRestrictions);
}
return effective;
}
@GuardedBy("mRestrictionsLock")
private void invalidateEffectiveUserRestrictionsRL(int userId) {
if (DBG) {
Log.d(LOG_TAG, "invalidateEffectiveUserRestrictions userId=" + userId);
}
mCachedEffectiveUserRestrictions.remove(userId);
}
private Bundle getEffectiveUserRestrictions(int userId) {
synchronized (mRestrictionsLock) {
Bundle restrictions = mCachedEffectiveUserRestrictions.get(userId);
if (restrictions == null) {
restrictions = computeEffectiveUserRestrictionsRL(userId);
mCachedEffectiveUserRestrictions.put(userId, restrictions);
}
return restrictions;
}
}
/** @return a specific user restriction that's in effect currently. */
@Override
public boolean hasUserRestriction(String restrictionKey, int userId) {
Bundle restrictions = getEffectiveUserRestrictions(userId);
return restrictions != null && restrictions.getBoolean(restrictionKey);
}
/**
* @return UserRestrictions that are in effect currently. This always returns a new
* {@link Bundle}.
*/
@Override
public Bundle getUserRestrictions(int userId) {
synchronized (mPackagesLock) {
Bundle restrictions = mUserRestrictions.get(userId);
return restrictions != null ? new Bundle(restrictions) : new Bundle();
}
Bundle restrictions = getEffectiveUserRestrictions(userId);
return restrictions != null ? new Bundle(restrictions) : new Bundle();
}
@Override
public void setUserRestriction(String key, boolean value, int userId) {
checkManageUsersPermission("setUserRestriction");
synchronized (mPackagesLock) {
if (!UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS.contains(key)) {
Bundle restrictions = getUserRestrictions(userId);
restrictions.putBoolean(key, value);
setUserRestrictionsInternalLocked(restrictions, userId);
}
if (!UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS.contains(key)) {
setUserRestrictionNoCheck(key, value, userId);
}
}
@Override
public void setSystemControlledUserRestriction(String key, boolean value, int userId) {
checkSystemOrRoot("setSystemControlledUserRestriction");
synchronized (mPackagesLock) {
Bundle restrictions = getUserRestrictions(userId);
restrictions.putBoolean(key, value);
setUserRestrictionsInternalLocked(restrictions, userId);
setUserRestrictionNoCheck(key, value, userId);
}
private void setUserRestrictionNoCheck(String key, boolean value, int userId) {
synchronized (mRestrictionsLock) {
// Note we can't modify Bundles stored in mBaseUserRestrictions directly, so create
// a copy.
final Bundle newRestrictions = new Bundle();
UserRestrictionsUtils.merge(newRestrictions, mBaseUserRestrictions.get(userId));
newRestrictions.putBoolean(key, value);
updateUserRestrictionsInternalRL(newRestrictions, userId);
}
}
@Override
public void setUserRestrictions(Bundle restrictions, int userId) {
checkManageUsersPermission("setUserRestrictions");
if (restrictions == null) return;
synchronized (mPackagesLock) {
final Bundle oldUserRestrictions = mUserRestrictions.get(userId);
// Restore the original state of system controlled restrictions from oldUserRestrictions
for (String key : UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS) {
restrictions.remove(key);
if (oldUserRestrictions.containsKey(key)) {
restrictions.putBoolean(key, oldUserRestrictions.getBoolean(key));
}
}
setUserRestrictionsInternalLocked(restrictions, userId);
/**
* Optionally updating user restrictions, calculate the effective user restrictions by
* consulting {@link com.android.server.devicepolicy.DevicePolicyManagerService} and also
* apply it to {@link com.android.server.AppOpsService}.
* TODO applyUserRestrictionsLocked() should also apply to system settings.
*
* @param newRestrictions User restrictions to set. If null, only the effective restrictions
* will be updated. Note don't pass an existing Bundle in {@link #mBaseUserRestrictions}
* or {@link #mCachedEffectiveUserRestrictions}; that'll most likely cause a sub
* @param userId target user ID.
*/
@GuardedBy("mRestrictionsLock")
private void updateUserRestrictionsInternalRL(
@Nullable Bundle newRestrictions, int userId) {
if (DBG) {
Log.d(LOG_TAG, "updateUserRestrictionsInternalLocked userId=" + userId
+ " bundle=" + newRestrictions);
}
final Bundle prevRestrictions = getEffectiveUserRestrictions(userId);
// Update system restrictions.
if (newRestrictions != null) {
// If newRestrictions == the current one, it's probably a bug.
Preconditions.checkState(mBaseUserRestrictions.get(userId) != newRestrictions);
Preconditions.checkState(mCachedEffectiveUserRestrictions.get(userId)
!= newRestrictions);
mBaseUserRestrictions.put(userId, newRestrictions);
}
mCachedEffectiveUserRestrictions.put(
userId, computeEffectiveUserRestrictionsRL(userId));
applyUserRestrictionsRL(userId, mBaseUserRestrictions.get(userId), prevRestrictions);
}
private void setUserRestrictionsInternalLocked(Bundle restrictions, int userId) {
final Bundle userRestrictions = mUserRestrictions.get(userId);
userRestrictions.clear();
userRestrictions.putAll(restrictions);
long token = Binder.clearCallingIdentity();
@GuardedBy("mRestrictionsLock")
private void applyUserRestrictionsRL(int userId,
Bundle newRestrictions, Bundle prevRestrictions) {
final long token = Binder.clearCallingIdentity();
try {
mAppOpsService.setUserRestrictions(userRestrictions, userId);
mAppOpsService.setUserRestrictions(newRestrictions, userId);
} catch (RemoteException e) {
Log.w(LOG_TAG, "Unable to notify AppOpsService of UserRestrictions");
} finally {
Binder.restoreCallingIdentity(token);
}
scheduleWriteUserLocked(mUsers.get(userId));
// TODO Move the code from DPMS.setUserRestriction().
}
@GuardedBy("mRestrictionsLock")
private void updateEffectiveUserRestrictionsRL(int userId) {
updateUserRestrictionsInternalRL(null, userId);
}
@GuardedBy("mRestrictionsLock")
private void updateEffectiveUserRestrictionsForAllUsersRL() {
// First, invalidate all cached values.
synchronized (mRestrictionsLock) {
mCachedEffectiveUserRestrictions.clear();
}
// We don't want to call into ActivityManagerNative while taking a lock, so we'll call
// it on a handler.
final Runnable r = new Runnable() {
@Override
public void run() {
// Then get the list of running users.
final int[] runningUsers;
try {
runningUsers = ActivityManagerNative.getDefault().getRunningUserIds();
} catch (RemoteException e) {
Log.w(LOG_TAG, "Unable to access ActivityManagerNative");
return;
}
// Then re-calculate the effective restrictions and apply, only for running users.
// It's okay if a new user has started after the getRunningUserIds() call,
// because we'll do the same thing (re-calculate the restrictions and apply)
// when we start a user.
// TODO: "Apply restrictions upon user start hasn't been implemented. Implement it.
synchronized (mRestrictionsLock) {
for (int i = 0; i < runningUsers.length; i++) {
updateUserRestrictionsInternalRL(null, runningUsers[i]);
}
}
}
};
mHandler.post(r);
}
/**
@@ -926,7 +1069,9 @@ public class UserManagerService extends IUserManager.Stub {
mUserVersion = USER_VERSION;
Bundle restrictions = new Bundle();
mUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions);
synchronized (mRestrictionsLock) {
mBaseUserRestrictions.append(UserHandle.USER_SYSTEM, restrictions);
}
updateUserIdsLocked();
initDefaultGuestRestrictions();
@@ -989,9 +1134,13 @@ public class UserManagerService extends IUserManager.Stub {
serializer.startTag(null, TAG_NAME);
serializer.text(userInfo.name);
serializer.endTag(null, TAG_NAME);
Bundle restrictions = mUserRestrictions.get(userInfo.id);
Bundle restrictions;
synchronized (mRestrictionsLock) {
restrictions = mBaseUserRestrictions.get(userInfo.id);
}
if (restrictions != null) {
UserRestrictionsUtils.writeRestrictions(serializer, restrictions, TAG_RESTRICTIONS);
UserRestrictionsUtils
.writeRestrictions(serializer, restrictions, TAG_RESTRICTIONS);
}
serializer.endTag(null, TAG_USER);
@@ -1131,7 +1280,9 @@ public class UserManagerService extends IUserManager.Stub {
userInfo.guestToRemove = guestToRemove;
userInfo.profileGroupId = profileGroupId;
userInfo.restrictedProfileParentId = restrictedProfileParentId;
mUserRestrictions.append(id, restrictions);
synchronized (mRestrictionsLock) {
mBaseUserRestrictions.append(id, restrictions);
}
return userInfo;
} catch (IOException ioe) {
@@ -1333,7 +1484,9 @@ public class UserManagerService extends IUserManager.Stub {
scheduleWriteUserLocked(userInfo);
updateUserIdsLocked();
Bundle restrictions = new Bundle();
mUserRestrictions.append(userId, restrictions);
synchronized (mRestrictionsLock) {
mBaseUserRestrictions.append(userId, restrictions);
}
}
}
mPm.newUserCreated(userId);
@@ -1616,25 +1769,6 @@ public class UserManagerService extends IUserManager.Stub {
}
}
@Override
public void removeRestrictions() {
checkManageUsersPermission("remove restrictions");
final int userHandle = UserHandle.getCallingUserId();
removeRestrictionsForUser(userHandle, true);
}
private void removeRestrictionsForUser(final int userHandle, boolean unhideApps) {
synchronized (mPackagesLock) {
// Remove all user restrictions
setUserRestrictions(new Bundle(), userHandle);
// Remove any app restrictions
cleanAppRestrictions(userHandle);
}
if (unhideApps) {
unhideAllInstalledAppsForUser(userHandle);
}
}
private void unhideAllInstalledAppsForUser(final int userHandle) {
mHandler.post(new Runnable() {
@Override
@@ -2062,7 +2196,10 @@ public class UserManagerService extends IUserManager.Stub {
}
pw.println(" Restrictions:");
UserRestrictionsUtils.dumpRestrictions(
pw, " ", mUserRestrictions.get(user.id));
pw, " ", mBaseUserRestrictions.get(user.id));
pw.println(" Effective restrictions:");
UserRestrictionsUtils.dumpRestrictions(
pw, " ", mCachedEffectiveUserRestrictions.get(user.id));
}
pw.println();
pw.println("Guest restrictions:");
@@ -2095,4 +2232,49 @@ public class UserManagerService extends IUserManager.Stub {
boolean isInitialized(int userId) {
return (getUserInfo(userId).flags & UserInfo.FLAG_INITIALIZED) != 0;
}
private class LocalService extends UserManagerInternal {
@Override
public Object getUserRestrictionsLock() {
return mRestrictionsLock;
}
@Override
@GuardedBy("mRestrictionsLock")
public void updateEffectiveUserRestrictionsRL(int userId) {
UserManagerService.this.updateEffectiveUserRestrictionsRL(userId);
}
@Override
@GuardedBy("mRestrictionsLock")
public void updateEffectiveUserRestrictionsForAllUsersRL() {
UserManagerService.this.updateEffectiveUserRestrictionsForAllUsersRL();
}
@Override
public Bundle getBaseUserRestrictions(int userId) {
synchronized (mRestrictionsLock) {
return mBaseUserRestrictions.get(userId);
}
}
@Override
public void setBaseUserRestrictionsByDpmsForMigration(
int userId, Bundle baseRestrictions) {
synchronized (mRestrictionsLock) {
mBaseUserRestrictions.put(userId, new Bundle(baseRestrictions));
invalidateEffectiveUserRestrictionsRL(userId);
}
synchronized (mPackagesLock) {
final UserInfo userInfo = mUsers.get(userId);
if (userInfo != null) {
writeUserLocked(userInfo);
} else {
Slog.w(LOG_TAG, "UserInfo not found for " + userId);
}
}
}
}
}

View File

@@ -86,7 +86,6 @@ public class UserRestrictionsUtils {
String tag) throws IOException {
serializer.startTag(null, tag);
for (String key : USER_RESTRICTIONS) {
//
if (restrictions.getBoolean(key)
&& !NON_PERSIST_USER_RESTRICTIONS.contains(key)) {
serializer.attribute(null, key, "true");
@@ -105,6 +104,17 @@ public class UserRestrictionsUtils {
}
}
public static void merge(Bundle dest, Bundle in) {
if (in == null) {
return;
}
for (String key : in.keySet()) {
if (in.getBoolean(key, false)) {
dest.putBoolean(key, true);
}
}
}
public static void dumpRestrictions(PrintWriter pw, String prefix, Bundle restrictions) {
boolean noneSet = true;
if (restrictions != null) {
@@ -114,9 +124,11 @@ public class UserRestrictionsUtils {
noneSet = false;
}
}
}
if (noneSet) {
pw.println(prefix + "none");
if (noneSet) {
pw.println(prefix + "none");
}
} else {
pw.println(prefix + "null");
}
}
}

View File

@@ -16,6 +16,8 @@
package com.android.server.devicepolicy;
import com.google.android.collect.Sets;
import static android.Manifest.permission.MANAGE_CA_CERTIFICATES;
import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
@@ -88,6 +90,7 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.os.storage.StorageManager;
import android.provider.ContactsContract.QuickContact;
import android.provider.ContactsInternal;
@@ -183,8 +186,6 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private static final int MONITORING_CERT_NOTIFICATION_ID = R.string.ssl_ca_cert_warning;
private static final int PROFILE_WIPED_NOTIFICATION_ID = 1001;
private static final boolean DBG = false;
private static final String ATTR_PERMISSION_PROVIDER = "permission-provider";
private static final String ATTR_SETUP_COMPLETE = "setup-complete";
private static final String ATTR_PERMISSION_POLICY = "permission-policy";
@@ -274,6 +275,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final Injector mInjector;
final IPackageManager mIPackageManager;
final UserManager mUserManager;
final UserManagerInternal mUserManagerInternal;
final LocalService mLocalService;
@@ -357,8 +359,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
getSendingUserId());
if (Intent.ACTION_BOOT_COMPLETED.equals(action)
|| ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) {
if (DBG) Slog.v(LOG_TAG, "Sending password expiration notifications for action "
+ action + " for user " + userHandle);
if (VERBOSE_LOG) {
Slog.v(LOG_TAG, "Sending password expiration notifications for action "
+ action + " for user " + userHandle);
}
mHandler.post(new Runnable() {
@Override
public void run() {
@@ -1014,7 +1018,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
private void handlePackagesChanged(String packageName, int userHandle) {
boolean removed = false;
if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
if (VERBOSE_LOG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
DevicePolicyData policy = getUserData(userHandle);
synchronized (this) {
for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
@@ -1079,6 +1083,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
return UserManager.get(mContext);
}
UserManagerInternal getUserManagerInternal() {
return LocalServices.getService(UserManagerInternal.class);
}
NotificationManager getNotificationManager() {
return mContext.getSystemService(NotificationManager.class);
}
@@ -1233,6 +1241,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mOwners = Preconditions.checkNotNull(injector.newOwners());
mUserManager = Preconditions.checkNotNull(injector.getUserManager());
mUserManagerInternal = Preconditions.checkNotNull(injector.getUserManagerInternal());
mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
mLocalService = new LocalService();
@@ -1327,10 +1336,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
synchronized (this) {
mOwners.load();
findOwnerComponentIfNecessaryLocked();
migrateUserRestrictionsIfNecessaryLocked();
// TODO PO may not have a class name either due to b/17652534. Address that too.
updateDeviceOwnerLocked();
// TODO Notify UM to update restrictions (?)
}
}
@@ -1350,14 +1362,113 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
if (doComponent == null) {
Slog.e(LOG_TAG, "Device-owner isn't registered as device-admin");
} else {
mOwners.setDeviceOwner(
mOwners.setDeviceOwnerWithRestrictionsMigrated(
doComponent,
mOwners.getDeviceOwnerName(),
mOwners.getDeviceOwnerUserId());
mOwners.getDeviceOwnerUserId(),
!mOwners.getDeviceOwnerUserRestrictionsNeedsMigration());
mOwners.writeDeviceOwner();
if (VERBOSE_LOG) {
Log.v(LOG_TAG, "Device owner component filled in");
}
}
}
/**
* We didn't use to persist user restrictions for each owners but only persisted in user
* manager.
*/
private void migrateUserRestrictionsIfNecessaryLocked() {
boolean migrated = false;
// Migrate for the DO. Basically all restrictions should be considered to be set by DO,
// except for the "system controlled" ones.
if (mOwners.getDeviceOwnerUserRestrictionsNeedsMigration()) {
if (VERBOSE_LOG) {
Log.v(LOG_TAG, "Migrating DO user restrictions");
}
migrated = true;
// Migrate user 0 restrictions to DO, except for "system" restrictions.
final ActiveAdmin deviceOwnerAdmin = getDeviceOwnerAdminLocked();
migrateUserRestrictionsForUser(UserHandle.SYSTEM, deviceOwnerAdmin,
/* exceptionList =*/ UserRestrictionsUtils.SYSTEM_CONTROLLED_USER_RESTRICTIONS);
mOwners.setDeviceOwnerUserRestrictionsMigrated();
}
// Migrate for POs. We have a few more exceptions.
final Set<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) {
final DevicePolicyData policy = getUserData(userId);
final int n = policy.mAdminList.size();
@@ -1373,7 +1484,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
nFound++;
}
}
if (nFound > 0) {
if (nFound > 1) {
Slog.w(LOG_TAG, "Multiple DA found; assume the first one is DO.");
}
return found;
@@ -1636,6 +1747,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
? mInjector.getDevicePolicyFilePathForSystemUser() + DEVICE_POLICIES_XML
: new File(mInjector.environmentGetUserSystemDirectory(userHandle),
DEVICE_POLICIES_XML).getAbsolutePath();
if (VERBOSE_LOG) {
Log.v(LOG_TAG, "Opening " + base);
}
return new JournaledFile(new File(base), new File(base + ".tmp"));
}
@@ -1808,7 +1922,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
try {
DeviceAdminInfo dai = findAdmin(
ComponentName.unflattenFromString(name), userHandle);
if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
if (VERBOSE_LOG
&& (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid)
!= userHandle)) {
Slog.w(LOG_TAG, "findAdmin returned an incorrect uid "
+ dai.getActivityInfo().applicationInfo.uid + " for user "
@@ -1988,8 +2103,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long token = mInjector.binderClearCallingIdentity();
try {
String value = cameraDisabled ? "1" : "0";
if (DBG) Slog.v(LOG_TAG, "Change in camera state ["
+ cameraPropertyForUser + "] = " + value);
if (VERBOSE_LOG) {
Slog.v(LOG_TAG, "Change in camera state ["
+ cameraPropertyForUser + "] = " + value);
}
mInjector.systemPropertiesSet(cameraPropertyForUser, value);
} finally {
mInjector.binderRestoreCallingIdentity(token);
@@ -4513,8 +4630,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
UserHandle callingUser = mInjector.binderGetCallingUserHandle();
// Check if this is the profile owner who is calling
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
final ActiveAdmin admin =
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
synchronized (this) {
admin.userRestrictions = null;
clearUserPoliciesLocked(callingUser);
final int userId = callingUser.getIdentifier();
mOwners.removeProfileOwner(userId);
@@ -4533,38 +4652,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
final long ident = mInjector.binderClearCallingIdentity();
try {
clearUserRestrictions(userHandle);
mIPackageManager.updatePermissionFlagsForAllApps(
PackageManager.FLAG_PERMISSION_POLICY_FIXED,
0 /* flagValues */, userHandle.getIdentifier());
// TODO This will not revert audio mute restrictions if they were set. b/24981972
synchronized (mUserManagerInternal.getUserRestrictionsLock()) {
mUserManagerInternal.updateEffectiveUserRestrictionsRL(userHandle.getIdentifier());
}
} catch (RemoteException re) {
} finally {
mInjector.binderRestoreCallingIdentity(ident);
}
}
private void clearUserRestrictions(UserHandle userHandle) {
Bundle userRestrictions = mUserManager.getUserRestrictions();
mUserManager.setUserRestrictions(new Bundle(), userHandle);
if (userRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)) {
try {
mInjector.getIAudioService().setMasterMute(true, 0, mContext.getPackageName(),
userHandle.getIdentifier());
} catch (RemoteException e) {
// Not much we can do here.
}
}
if (userRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE)) {
try {
mInjector.getIAudioService().setMicrophoneMute(true, mContext.getPackageName(),
userHandle.getIdentifier());
} catch (RemoteException e) {
// Not much we can do here.
}
}
}
@Override
public boolean hasUserSetupCompleted() {
return hasUserSetupCompleted(UserHandle.getCallingUserId());
@@ -5503,95 +5603,123 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
@Override
public void setUserRestriction(ComponentName who, String key, boolean enabled) {
public void setUserRestriction(ComponentName who, String key, boolean enabledFromThisOwner) {
Preconditions.checkNotNull(who, "ComponentName is null");
final int userHandle = mInjector.userHandleGetCallingUserId();
final UserHandle user = new UserHandle(userHandle);
synchronized (this) {
ActiveAdmin activeAdmin =
getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
boolean isDeviceOwner = isDeviceOwner(who);
if (!isDeviceOwner && userHandle != UserHandle.USER_SYSTEM
&& DEVICE_OWNER_USER_RESTRICTIONS.contains(key)) {
throw new SecurityException("Profile owners cannot set user restriction " + key);
}
if (IMMUTABLE_USER_RESTRICTIONS.contains(key)) {
throw new SecurityException("User restriction " + key + " cannot be changed");
}
boolean alreadyRestricted = mUserManager.hasUserRestriction(key, user);
synchronized (mUserManagerInternal.getUserRestrictionsLock()) {
synchronized (this) {
ActiveAdmin activeAdmin =
getActiveAdminForCallerLocked(who,
DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
boolean isDeviceOwner = isDeviceOwner(who);
if (!isDeviceOwner && userHandle != UserHandle.USER_SYSTEM
&& DEVICE_OWNER_USER_RESTRICTIONS.contains(key)) {
throw new SecurityException(
"Profile owners cannot set user restriction " + key);
}
if (IMMUTABLE_USER_RESTRICTIONS.contains(key)) {
throw new SecurityException("User restriction " + key + " cannot be changed");
}
long id = mInjector.binderClearCallingIdentity();
try {
if (enabled && !alreadyRestricted) {
if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
mInjector.getIAudioService()
.setMicrophoneMute(true, mContext.getPackageName(), userHandle);
} else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
mInjector.getIAudioService()
.setMasterMute(true, 0, mContext.getPackageName(), userHandle);
} else if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) {
mInjector.settingsSecurePutIntForUser(
Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0,
userHandle);
} else if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) {
mInjector.settingsSecurePutIntForUser(
Settings.Secure.LOCATION_MODE, Settings.Secure.LOCATION_MODE_OFF,
userHandle);
mInjector.settingsSecurePutStringForUser(
Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "",
userHandle);
} else if (UserManager.DISALLOW_DEBUGGING_FEATURES.equals(key)) {
// Only disable adb if changing for system user, since it is global
// TODO: should this be admin user?
if (userHandle == UserHandle.USER_SYSTEM) {
final long id = mInjector.binderClearCallingIdentity();
try {
// Original value.
final boolean alreadyRestricted = mUserManager.hasUserRestriction(key, user);
// Save the restriction to ActiveAdmin.
// TODO When DO sets a restriction, it'll always be treated as device-wide.
// If there'll be a policy that can be set by both, we'll need scoping support,
// and need to have another Bundle in DO active admin to hold restrictions as
// PO.
activeAdmin.ensureUserRestrictions().putBoolean(key, enabledFromThisOwner);
saveSettingsLocked(userHandle);
// Tell UserManager the new value. Note this needs to be done before calling
// into AudioService, because AS will check AppOps that'll be updated by UM.
if (isDeviceOwner) {
mUserManagerInternal.updateEffectiveUserRestrictionsForAllUsersRL();
} else {
mUserManagerInternal.updateEffectiveUserRestrictionsRL(userHandle);
}
// New value.
final boolean enabled = mUserManager.hasUserRestriction(key, user);
// TODO The rest of the code should move to UserManagerService.
if (enabled && !alreadyRestricted) {
if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
mInjector.getIAudioService()
.setMicrophoneMute(true, mContext.getPackageName(), userHandle);
} else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
mInjector.getIAudioService()
.setMasterMute(true, 0, mContext.getPackageName(), userHandle);
} else if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) {
mInjector.settingsSecurePutIntForUser(
Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0,
userHandle);
} else if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) {
mInjector.settingsSecurePutIntForUser(
Settings.Secure.LOCATION_MODE,
Settings.Secure.LOCATION_MODE_OFF,
userHandle);
mInjector.settingsSecurePutStringForUser(
Settings.Secure.LOCATION_PROVIDERS_ALLOWED, "",
userHandle);
} else if (UserManager.DISALLOW_DEBUGGING_FEATURES.equals(key)) {
// Only disable adb if changing for system user, since it is global
// TODO: should this be admin user?
if (userHandle == UserHandle.USER_SYSTEM) {
mInjector.settingsGlobalPutStringForUser(
Settings.Global.ADB_ENABLED, "0", userHandle);
}
} else if (UserManager.ENSURE_VERIFY_APPS.equals(key)) {
mInjector.settingsGlobalPutStringForUser(
Settings.Global.ADB_ENABLED, "0", userHandle);
Settings.Global.PACKAGE_VERIFIER_ENABLE, "1",
userHandle);
mInjector.settingsGlobalPutStringForUser(
Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, "1",
userHandle);
} else if (UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES.equals(key)) {
mInjector.settingsSecurePutIntForUser(
Settings.Secure.INSTALL_NON_MARKET_APPS, 0,
userHandle);
}
} else if (UserManager.ENSURE_VERIFY_APPS.equals(key)) {
mInjector.settingsGlobalPutStringForUser(
Settings.Global.PACKAGE_VERIFIER_ENABLE, "1",
userHandle);
mInjector.settingsGlobalPutStringForUser(
Settings.Global.PACKAGE_VERIFIER_INCLUDE_ADB, "1",
userHandle);
} else if (UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES.equals(key)) {
mInjector.settingsSecurePutIntForUser(
Settings.Secure.INSTALL_NON_MARKET_APPS, 0,
userHandle);
}
}
mUserManager.setUserRestriction(key, enabled, user);
activeAdmin.ensureUserRestrictions().putBoolean(key, enabled);
saveSettingsLocked(userHandle);
if (enabled != alreadyRestricted) {
if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) {
// Send out notifications however as some clients may want to reread the
// value which actually changed due to a restriction having been applied.
final String property = Settings.Secure.SYS_PROP_SETTING_VERSION;
long version = mInjector.systemPropertiesGetLong(property, 0) + 1;
mInjector.systemPropertiesSet(property, Long.toString(version));
if (enabled != alreadyRestricted) {
if (UserManager.DISALLOW_SHARE_LOCATION.equals(key)) {
// Send out notifications however as some clients may want to reread the
// value which actually changed due to a restriction having been
// applied.
final String property = Settings.Secure.SYS_PROP_SETTING_VERSION;
long version = mInjector.systemPropertiesGetLong(property, 0) + 1;
mInjector.systemPropertiesSet(property, Long.toString(version));
final String name = Settings.Secure.LOCATION_PROVIDERS_ALLOWED;
Uri url = Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
mContext.getContentResolver().notifyChange(url, null, true, userHandle);
final String name = Settings.Secure.LOCATION_PROVIDERS_ALLOWED;
Uri url = Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
mContext.getContentResolver().notifyChange(url, null, true, userHandle);
}
}
}
if (!enabled && alreadyRestricted) {
if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
mInjector.getIAudioService()
.setMicrophoneMute(false, mContext.getPackageName(), userHandle);
} else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
mInjector.getIAudioService()
.setMasterMute(false, 0, mContext.getPackageName(), userHandle);
if (!enabled && alreadyRestricted) {
if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
mInjector.getIAudioService()
.setMicrophoneMute(false, mContext.getPackageName(),
userHandle);
} else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
mInjector.getIAudioService()
.setMasterMute(false, 0, mContext.getPackageName(), userHandle);
}
}
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Failed to talk to AudioService.", re);
} finally {
mInjector.binderRestoreCallingIdentity(id);
}
} catch (RemoteException re) {
Slog.e(LOG_TAG, "Failed to talk to AudioService.", re);
} finally {
mInjector.binderRestoreCallingIdentity(id);
sendChangedNotification(userHandle);
}
sendChangedNotification(userHandle);
}
}
@@ -5650,7 +5778,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
long id = mInjector.binderClearCallingIdentity();
try {
if (DBG) {
if (VERBOSE_LOG) {
Slog.v(LOG_TAG, "installing " + packageName + " for "
+ userId);
}
@@ -5705,7 +5833,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
0, // no flags
primaryUser.id);
if (DBG) Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
if (VERBOSE_LOG) {
Slog.d(LOG_TAG, "Enabling system activities: " + activitiesToEnable);
}
int numberOfAppsInstalled = 0;
if (activitiesToEnable != null) {
for (ResolveInfo info : activitiesToEnable) {
@@ -6275,7 +6405,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
private final class LocalService extends DevicePolicyManagerInternal {
@VisibleForTesting
final class LocalService extends DevicePolicyManagerInternal {
private List<OnCrossProfileWidgetProvidersChangeListener> mWidgetProviderListeners;
@Override
@@ -6322,6 +6453,30 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
}
@Override
public Bundle getComposedUserRestrictions(int userId, Bundle inBundle) {
synchronized (DevicePolicyManagerService.this) {
final ActiveAdmin deviceOwner = getDeviceOwnerAdminLocked();
final ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userId);
final Bundle deviceOwnerRestrictions =
deviceOwner == null ? null : deviceOwner.userRestrictions;
final Bundle profileOwnerRestrictions =
profileOwner == null ? null : profileOwner.userRestrictions;
if (deviceOwnerRestrictions == null && profileOwnerRestrictions == null) {
// No restrictions to merge.
return inBundle;
}
final Bundle composed = new Bundle(inBundle);
UserRestrictionsUtils.merge(composed, deviceOwnerRestrictions);
UserRestrictionsUtils.merge(composed, profileOwnerRestrictions);
return composed;
}
}
private void notifyCrossProfileProvidersChanged(int userId, List<String> packages) {
final List<OnCrossProfileWidgetProvidersChangeListener> listeners;
synchronized (DevicePolicyManagerService.this) {

View File

@@ -30,7 +30,6 @@ import android.util.Slog;
import android.util.Xml;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.Preconditions;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -75,6 +74,7 @@ class Owners {
private static final String ATTR_PACKAGE = "package";
private static final String ATTR_COMPONENT_NAME = "component";
private static final String ATTR_USERID = "userId";
private static final String ATTR_USER_RESTRICTIONS_MIGRATED = "userRestrictionsMigrated";
private static final String TAG_SYSTEM_UPDATE_POLICY = "system-update-policy";
@@ -155,7 +155,16 @@ class Owners {
Slog.e(TAG, "Invalid user id for device owner user: " + userId);
return;
}
mDeviceOwner = new OwnerInfo(ownerName, admin);
// For a newly set DO, there's no need for migration.
setDeviceOwnerWithRestrictionsMigrated(admin, ownerName, userId,
/* userRestrictionsMigrated =*/ true);
}
// Note this should be only called during migration. Normally when DO is set,
// userRestrictionsMigrated should always be true.
void setDeviceOwnerWithRestrictionsMigrated(ComponentName admin, String ownerName, int userId,
boolean userRestrictionsMigrated) {
mDeviceOwner = new OwnerInfo(ownerName, admin, userRestrictionsMigrated);
mDeviceOwnerUserId = userId;
}
@@ -165,7 +174,9 @@ class Owners {
}
void setProfileOwner(ComponentName admin, String ownerName, int userId) {
mProfileOwners.put(userId, new OwnerInfo(ownerName, admin));
// For a newly set PO, there's no need for migration.
mProfileOwners.put(userId, new OwnerInfo(ownerName, admin,
/* userRestrictionsMigrated =*/ true));
}
void removeProfileOwner(int userId) {
@@ -207,6 +218,38 @@ class Owners {
return mDeviceOwner != null;
}
/**
* @return true if user restrictions need to be migrated for DO.
*/
boolean getDeviceOwnerUserRestrictionsNeedsMigration() {
return mDeviceOwner != null && !mDeviceOwner.userRestrictionsMigrated;
}
/**
* @return true if user restrictions need to be migrated for PO.
*/
boolean getProfileOwnerUserRestrictionsNeedsMigration(int userId) {
OwnerInfo profileOwner = mProfileOwners.get(userId);
return profileOwner != null && !profileOwner.userRestrictionsMigrated;
}
/** Sets the user restrictions migrated flag, and also writes to the file. */
void setDeviceOwnerUserRestrictionsMigrated() {
if (mDeviceOwner != null) {
mDeviceOwner.userRestrictionsMigrated = true;
}
writeDeviceOwner();
}
/** Sets the user restrictions migrated flag, and also writes to the file. */
void setProfileOwnerUserRestrictionsMigrated(int userId) {
OwnerInfo profileOwner = mProfileOwners.get(userId);
if (profileOwner != null) {
profileOwner.userRestrictionsMigrated = true;
}
writeProfileOwner(userId);
}
private boolean readLegacyOwnerFile(File file) {
if (!file.exists()) {
// Already migrated or the device has no owners.
@@ -226,7 +269,8 @@ class Owners {
if (tag.equals(TAG_DEVICE_OWNER)) {
String name = parser.getAttributeValue(null, ATTR_NAME);
String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);
mDeviceOwner = new OwnerInfo(name, packageName);
mDeviceOwner = new OwnerInfo(name, packageName,
/* userRestrictionsMigrated =*/ false);
mDeviceOwnerUserId = UserHandle.USER_SYSTEM;
} else if (tag.equals(TAG_DEVICE_INITIALIZER)) {
// Deprecated tag
@@ -241,7 +285,8 @@ class Owners {
ComponentName admin = ComponentName.unflattenFromString(
profileOwnerComponentStr);
if (admin != null) {
profileOwnerInfo = new OwnerInfo(profileOwnerName, admin);
profileOwnerInfo = new OwnerInfo(profileOwnerName, admin,
/* userRestrictionsMigrated =*/ false);
} else {
// This shouldn't happen but switch from package name -> component name
// might have written bad device owner files. b/17652534
@@ -250,7 +295,8 @@ class Owners {
}
}
if (profileOwnerInfo == null) {
profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName);
profileOwnerInfo = new OwnerInfo(profileOwnerName, profileOwnerPackageName,
/* userRestrictionsMigrated =*/ false);
}
mProfileOwners.put(userId, profileOwnerInfo);
} else if (TAG_SYSTEM_UPDATE_POLICY.equals(tag)) {
@@ -503,21 +549,24 @@ class Owners {
}
}
private static class OwnerInfo {
static class OwnerInfo {
public final String name;
public final String packageName;
public final ComponentName admin;
public boolean userRestrictionsMigrated;
public OwnerInfo(String name, String packageName) {
public OwnerInfo(String name, String packageName, boolean userRestrictionsMigrated) {
this.name = name;
this.packageName = packageName;
this.admin = new ComponentName(packageName, "");
this.userRestrictionsMigrated = userRestrictionsMigrated;
}
public OwnerInfo(String name, ComponentName admin) {
public OwnerInfo(String name, ComponentName admin, boolean userRestrictionsMigrated) {
this.name = name;
this.admin = admin;
this.packageName = admin.getPackageName();
this.userRestrictionsMigrated = userRestrictionsMigrated;
}
public void writeToXml(XmlSerializer out, String tag) throws IOException {
@@ -529,6 +578,8 @@ class Owners {
if (admin != null) {
out.attribute(null, ATTR_COMPONENT_NAME, admin.flattenToString());
}
out.attribute(null, ATTR_USER_RESTRICTIONS_MIGRATED,
String.valueOf(userRestrictionsMigrated));
out.endTag(null, tag);
}
@@ -537,12 +588,16 @@ class Owners {
final String name = parser.getAttributeValue(null, ATTR_NAME);
final String componentName =
parser.getAttributeValue(null, ATTR_COMPONENT_NAME);
final String userRestrictionsMigratedStr =
parser.getAttributeValue(null, ATTR_USER_RESTRICTIONS_MIGRATED);
final boolean userRestrictionsMigrated =
("true".equals(userRestrictionsMigratedStr));
// Has component name? If so, return [name, component]
if (componentName != null) {
final ComponentName admin = ComponentName.unflattenFromString(componentName);
if (admin != null) {
return new OwnerInfo(name, admin);
return new OwnerInfo(name, admin, userRestrictionsMigrated);
} else {
// This shouldn't happen but switch from package name -> component name
// might have written bad device owner files. b/17652534
@@ -552,7 +607,7 @@ class Owners {
}
// Else, build with [name, package]
return new OwnerInfo(name, packageName);
return new OwnerInfo(name, packageName, userRestrictionsMigrated);
}
public void dump(String prefix, PrintWriter pw) {

View File

@@ -0,0 +1,4 @@
<?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" />

View File

@@ -0,0 +1,7 @@
<?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>

View File

@@ -0,0 +1,5 @@
<?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>

View File

@@ -0,0 +1,5 @@
<?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>

View File

@@ -0,0 +1,190 @@
/*
* Copyright (C) 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.devicepolicy;
import com.android.server.LocalServices;
import com.android.server.SystemService;
import com.android.server.devicepolicy.DevicePolicyManagerServiceTestable.OwnersTestable;
import android.app.admin.DevicePolicyManager;
import android.app.admin.DevicePolicyManagerInternal;
import android.content.pm.PackageManager;
import android.content.pm.UserInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.os.UserManager;
import android.util.Pair;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.when;
public class DevicePolicyManagerServiceMigrationTest extends DpmTestBase {
private DpmMockContext mContext;
@Override
protected void setUp() throws Exception {
super.setUp();
mContext = getContext();
when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
.thenReturn(true);
}
public void testMigration() throws Exception {
final File user10dir = mMockContext.addUser(10, 0);
final File user11dir = mMockContext.addUser(11, UserInfo.FLAG_MANAGED_PROFILE);
final File user12dir = mMockContext.addUser(12, 0);
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
setUpPackageManagerForAdmin(admin2, UserHandle.getUid(10, 123));
setUpPackageManagerForAdmin(admin3, UserHandle.getUid(11, 456));
// Create the legacy owners & policies file.
DpmTestUtils.writeToFile(
(new File(mContext.dataDir, OwnersTestable.LEGACY_FILE)).getAbsoluteFile(),
DpmTestUtils.readAsset(mRealTestContext,
"DevicePolicyManagerServiceMigrationTest/legacy_device_owner.xml"));
DpmTestUtils.writeToFile(
(new File(mContext.systemUserDataDir, "device_policies.xml")).getAbsoluteFile(),
DpmTestUtils.readAsset(mRealTestContext,
"DevicePolicyManagerServiceMigrationTest/legacy_device_policies.xml"));
DpmTestUtils.writeToFile(
(new File(user10dir, "device_policies.xml")).getAbsoluteFile(),
DpmTestUtils.readAsset(mRealTestContext,
"DevicePolicyManagerServiceMigrationTest/legacy_device_policies_10.xml"));
DpmTestUtils.writeToFile(
(new File(user11dir, "device_policies.xml")).getAbsoluteFile(),
DpmTestUtils.readAsset(mRealTestContext,
"DevicePolicyManagerServiceMigrationTest/legacy_device_policies_11.xml"));
// Set up UserManager
when(mMockContext.userManagerInternal.getBaseUserRestrictions(
eq(UserHandle.USER_SYSTEM))).thenReturn(DpmTestUtils.newRestrictions(
UserManager.DISALLOW_ADD_USER,
UserManager.DISALLOW_RECORD_AUDIO));
when(mMockContext.userManagerInternal.getBaseUserRestrictions(
eq(10))).thenReturn(DpmTestUtils.newRestrictions(
UserManager.DISALLOW_REMOVE_USER,
UserManager.DISALLOW_SMS,
UserManager.DISALLOW_OUTGOING_CALLS,
UserManager.DISALLOW_WALLPAPER,
UserManager.DISALLOW_RECORD_AUDIO));
when(mMockContext.userManagerInternal.getBaseUserRestrictions(
eq(11))).thenReturn(DpmTestUtils.newRestrictions(
UserManager.DISALLOW_REMOVE_USER,
UserManager.DISALLOW_SMS,
UserManager.DISALLOW_OUTGOING_CALLS,
UserManager.DISALLOW_WALLPAPER,
UserManager.DISALLOW_RECORD_AUDIO));
final Map<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());
}
}

View File

@@ -27,6 +27,7 @@ import android.os.Looper;
import android.os.PowerManagerInternal;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.view.IWindowManager;
import java.io.File;
@@ -106,6 +107,11 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
return context.userManager;
}
@Override
UserManagerInternal getUserManagerInternal() {
return context.userManagerInternal;
}
@Override
PowerManagerInternal getPowerManagerInternal() {
return context.powerManagerInternal;
@@ -153,7 +159,7 @@ public class DevicePolicyManagerServiceTestable extends DevicePolicyManagerServi
@Override
String getDevicePolicyFilePathForSystemUser() {
return context.systemUserDataDir.getAbsolutePath();
return context.systemUserDataDir.getAbsolutePath() + "/";
}
@Override

View File

@@ -27,7 +27,6 @@ import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
@@ -70,9 +69,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
private DpmMockContext mContext;
public DevicePolicyManager dpm;
public DevicePolicyManagerServiceTestable dpms;
public ComponentName admin1;
public ComponentName admin2;
public ComponentName admin3;
@Override
protected void setUp() throws Exception {
@@ -85,10 +81,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
initializeDpms();
admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class);
admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class);
admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class);
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_UID);
setUpPackageManagerForAdmin(admin2, DpmMockContext.CALLER_UID);
setUpPackageManagerForAdmin(admin3, DpmMockContext.CALLER_UID);
@@ -113,67 +105,6 @@ public class DevicePolicyManagerTest extends DpmTestBase {
}
}
private void setUpPackageManagerForAdmin(ComponentName admin, int packageUid) throws Exception {
setUpPackageManagerForAdmin(admin, packageUid,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
}
private void setUpPackageManagerForAdmin(ComponentName admin, int packageUid,
int enabledSetting) throws Exception {
// Set up queryBroadcastReceivers().
final Intent resolveIntent = new Intent();
resolveIntent.setComponent(admin);
final List<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<>();
@@ -220,7 +151,7 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
// Check
assertEquals(admin1, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE));
assertEquals(admin, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE));
}
public void testHasNoFeature() throws Exception {
@@ -743,6 +674,8 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertEquals("", dpms.getDeviceOwner().getClassName());
// Then create a new DPMS to have it load the settings from files.
when(mContext.userManager.getUserRestrictions(any(UserHandle.class)))
.thenReturn(new Bundle());
initializeDpms();
// Now the DO component name is a full name.
@@ -802,32 +735,33 @@ public class DevicePolicyManagerTest extends DpmTestBase {
assertTrue(dpm.setDeviceOwner(admin1, "owner-name",
UserHandle.USER_SYSTEM));
assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_SMS));
assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(),
dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_SMS);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
assertTrue(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_SMS));
assertTrue(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
UserManager.DISALLOW_SMS, UserManager.DISALLOW_OUTGOING_CALLS),
dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
);
dpm.clearUserRestriction(admin1, UserManager.DISALLOW_SMS);
assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_SMS));
assertTrue(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS),
dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
);
dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_SMS));
assertFalse(dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(),
dpms.getDeviceOwnerAdminLocked().ensureUserRestrictions()
);
// TODO Check inner calls.
// TODO Make sure restrictions are written to the file.
@@ -836,42 +770,106 @@ public class DevicePolicyManagerTest extends DpmTestBase {
public void testSetUserRestriction_asPo() {
setAsProfileOwner(admin1);
assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
.ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES));
assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
.ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(),
dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
.ensureUserRestrictions()
);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
dpm.addUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
assertTrue(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
.ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES));
assertTrue(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
.ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES,
UserManager.DISALLOW_OUTGOING_CALLS
),
dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
.ensureUserRestrictions()
);
dpm.clearUserRestriction(admin1, UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES);
assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
.ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES));
assertTrue(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
.ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(
UserManager.DISALLOW_OUTGOING_CALLS
),
dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
.ensureUserRestrictions()
);
dpm.clearUserRestriction(admin1, UserManager.DISALLOW_OUTGOING_CALLS);
assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
.ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_INSTALL_UNKNOWN_SOURCES));
assertFalse(dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
.ensureUserRestrictions()
.getBoolean(UserManager.DISALLOW_OUTGOING_CALLS));
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions(),
dpms.getProfileOwnerAdminLocked(DpmMockContext.CALLER_USER_HANDLE)
.ensureUserRestrictions()
);
// TODO Check inner calls.
// TODO Make sure restrictions are written to the file.
}
public void testGetComposedUserRestrictions_noDoNoPo() throws Exception {
final Bundle in = DpmTestUtils.newRestrictions(UserManager.DISALLOW_OUTGOING_CALLS);
Bundle actual = dpms.mLocalService.getComposedUserRestrictions(
UserHandle.USER_SYSTEM, in);
assertTrue(in == actual);
actual = dpms.mLocalService.getComposedUserRestrictions(
DpmMockContext.CALLER_USER_HANDLE, in);
assertTrue(in == actual);
}
public void testGetComposedUserRestrictions() throws Exception {
mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
// First, set DO.
// Call from a process on the system user.
mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
// Make sure admin1 is installed on system user.
setUpPackageManagerForAdmin(admin1, DpmMockContext.CALLER_SYSTEM_USER_UID);
// Call.
dpm.setActiveAdmin(admin1, /* replace =*/ false, UserHandle.USER_SYSTEM);
assertTrue(dpm.setDeviceOwner(admin1, "owner-name",
UserHandle.USER_SYSTEM));
dpm.addUserRestriction(admin1, "rest1");
dpm.addUserRestriction(admin1, "rest2");
// Set PO on CALLER_USER_HANDLE.
mContext.binder.callingUid = DpmMockContext.CALLER_UID;
setAsProfileOwner(admin2);
dpm.addUserRestriction(admin2, "restA");
dpm.addUserRestriction(admin2, "restB");
final Bundle in = DpmTestUtils.newRestrictions("abc");
Bundle actual = dpms.mLocalService.getComposedUserRestrictions(
UserHandle.USER_SYSTEM, in);
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions("abc", "rest1", "rest2"),
actual);
actual = dpms.mLocalService.getComposedUserRestrictions(
DpmMockContext.CALLER_USER_HANDLE, in);
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions("abc", "rest1", "rest2", "restA", "restB"),
actual);
actual = dpms.mLocalService.getComposedUserRestrictions(
DpmMockContext.CALLER_USER_HANDLE + 1, in);
DpmTestUtils.assertRestrictions(
DpmTestUtils.newRestrictions("abc", "rest1", "rest2"),
actual);
}
}

View File

@@ -36,6 +36,7 @@ import android.os.PowerManager.WakeLock;
import android.os.PowerManagerInternal;
import android.os.UserHandle;
import android.os.UserManager;
import android.os.UserManagerInternal;
import android.test.mock.MockContentResolver;
import android.test.mock.MockContext;
import android.view.IWindowManager;
@@ -203,6 +204,7 @@ public class DpmMockContext extends MockContext {
public final EnvironmentForMock environment;
public final SystemPropertiesForMock systemProperties;
public final UserManager userManager;
public final UserManagerInternal userManagerInternal;
public final UserManagerForMock userManagerForMock;
public final PowerManagerForMock powerManager;
public final PowerManagerInternal powerManagerInternal;
@@ -233,6 +235,7 @@ public class DpmMockContext extends MockContext {
environment = mock(EnvironmentForMock.class);
systemProperties= mock(SystemPropertiesForMock.class);
userManager = mock(UserManager.class);
userManagerInternal = mock(UserManagerInternal.class);
userManagerForMock = mock(UserManagerForMock.class);
powerManager = mock(PowerManagerForMock.class);
powerManagerInternal = mock(PowerManagerInternal.class);
@@ -257,6 +260,9 @@ public class DpmMockContext extends MockContext {
// System user is always running.
setUserRunning(UserHandle.USER_SYSTEM, true);
// This method must return an object.
when(userManagerInternal.getUserRestrictionsLock()).thenReturn(new Object());
}
public File addUser(int userId, int flags) {

View File

@@ -16,10 +16,21 @@
package com.android.server.devicepolicy;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.UserHandle;
import android.test.AndroidTestCase;
import java.io.File;
import java.util.List;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.doReturn;
public abstract class DpmTestBase extends AndroidTestCase {
public static final String TAG = "DpmTest";
@@ -29,6 +40,10 @@ public abstract class DpmTestBase extends AndroidTestCase {
public File dataDir;
public ComponentName admin1;
public ComponentName admin2;
public ComponentName admin3;
@Override
protected void setUp() throws Exception {
super.setUp();
@@ -37,10 +52,77 @@ public abstract class DpmTestBase extends AndroidTestCase {
mMockContext = new DpmMockContext(
mRealTestContext, new File(mRealTestContext.getCacheDir(), "test-data"));
admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class);
admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class);
admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class);
}
@Override
public DpmMockContext getContext() {
return mMockContext;
}
protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid)
throws Exception {
setUpPackageManagerForAdmin(admin, packageUid,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
}
protected void setUpPackageManagerForAdmin(ComponentName admin, int packageUid,
int enabledSetting) throws Exception {
// Set up queryBroadcastReceivers().
final Intent resolveIntent = new Intent();
resolveIntent.setComponent(admin);
final List<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)));
}
}

View File

@@ -16,21 +16,35 @@
package com.android.server.devicepolicy;
import com.google.android.collect.Lists;
import com.google.android.collect.Sets;
import android.content.Context;
import android.os.Bundle;
import android.os.FileUtils;
import android.os.Parcel;
import android.os.Parcelable;
import android.test.AndroidTestCase;
import android.util.Log;
import android.util.Printer;
import org.junit.Assert;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.Set;
public class DpmTestUtils {
private DpmTestUtils() {
}
import junit.framework.AssertionFailedError;
public class DpmTestUtils extends AndroidTestCase {
public static void clearDir(File dir) {
if (dir.exists()) {
Assert.assertTrue("failed to delete dir", FileUtils.deleteContents(dir));
@@ -43,6 +57,44 @@ public class DpmTestUtils {
return list == null ? 0 : list.size();
}
public static Bundle newRestrictions(String... restrictions) {
final Bundle ret = new Bundle();
for (String restriction : restrictions) {
ret.putBoolean(restriction, true);
}
return ret;
}
public static void assertRestrictions(Bundle expected, Bundle actual) {
final ArrayList<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);
@@ -58,4 +110,57 @@ public class DpmTestUtils {
Log.i(DpmTestBase.TAG, x);
}
};
public static String readAsset(Context context, String assetPath) throws IOException {
final StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(
new InputStreamReader(
context.getResources().getAssets().open(assetPath)))) {
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append(System.lineSeparator());
}
}
return sb.toString();
}
public static void writeToFile(File path, String content)
throws IOException {
path.getParentFile().mkdirs();
try (FileWriter writer = new FileWriter(path)) {
Log.i(DpmTestBase.TAG, "Writing to " + path);
Log.i(DpmTestBase.TAG, content);
writer.write(content);
}
}
private static boolean checkAssertRestrictions(Bundle a, Bundle b) {
try {
assertRestrictions(a, b);
return true;
} catch (AssertionFailedError e) {
return false;
}
}
public void testAssertRestrictions() {
final Bundle a = newRestrictions();
final Bundle b = newRestrictions("a");
final Bundle c = newRestrictions("a");
final Bundle d = newRestrictions("b", "c");
final Bundle e = newRestrictions("b", "c");
assertTrue(checkAssertRestrictions(null, null));
assertFalse(checkAssertRestrictions(null, a));
assertFalse(checkAssertRestrictions(a, null));
assertTrue(checkAssertRestrictions(a, a));
assertFalse(checkAssertRestrictions(a, b));
assertTrue(checkAssertRestrictions(b, c));
assertFalse(checkAssertRestrictions(c, d));
assertTrue(checkAssertRestrictions(d, e));
}
}

View File

@@ -47,31 +47,6 @@ import static org.mockito.Mockito.when;
(mmma frameworks/base/services/tests/servicestests/ for non-ninja build)
*/
public class OwnersTest extends DpmTestBase {
private String readAsset(String assetPath) throws IOException {
final StringBuilder sb = new StringBuilder();
try (BufferedReader br = new BufferedReader(
new InputStreamReader(
mRealTestContext.getResources().getAssets().open(assetPath)))) {
String line;
while ((line = br.readLine()) != null) {
sb.append(line);
sb.append(System.lineSeparator());
}
}
return sb.toString();
}
private void createLegacyFile(File path, String content)
throws IOException {
path.getParentFile().mkdirs();
try (FileWriter writer = new FileWriter(path)) {
Log.i(TAG, "Writing to " + path);
Log.i(TAG, content);
writer.write(content);
}
}
public void testUpgrade01() throws Exception {
getContext().addUsers(10, 11, 20, 21);
@@ -79,8 +54,8 @@ public class OwnersTest extends DpmTestBase {
{
final OwnersTestable owners = new OwnersTestable(getContext());
createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
readAsset("OwnersTest/test01/input.xml"));
DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test01/input.xml"));
owners.load();
@@ -99,6 +74,12 @@ public class OwnersTest extends DpmTestBase {
assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId());
assertNull(owners.getSystemUpdatePolicy());
assertEquals(0, owners.getProfileOwnerKeys().size());
assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
}
// Then re-read and check.
@@ -110,6 +91,12 @@ public class OwnersTest extends DpmTestBase {
assertEquals(UserHandle.USER_NULL, owners.getDeviceOwnerUserId());
assertNull(owners.getSystemUpdatePolicy());
assertEquals(0, owners.getProfileOwnerKeys().size());
assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
}
}
@@ -120,8 +107,8 @@ public class OwnersTest extends DpmTestBase {
{
final OwnersTestable owners = new OwnersTestable(getContext());
createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
readAsset("OwnersTest/test02/input.xml"));
DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test02/input.xml"));
owners.load();
@@ -142,6 +129,12 @@ public class OwnersTest extends DpmTestBase {
assertNull(owners.getSystemUpdatePolicy());
assertEquals(0, owners.getProfileOwnerKeys().size());
assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
}
// Then re-read and check.
@@ -156,6 +149,12 @@ public class OwnersTest extends DpmTestBase {
assertNull(owners.getSystemUpdatePolicy());
assertEquals(0, owners.getProfileOwnerKeys().size());
assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
}
}
@@ -166,8 +165,8 @@ public class OwnersTest extends DpmTestBase {
{
final OwnersTestable owners = new OwnersTestable(getContext());
createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
readAsset("OwnersTest/test03/input.xml"));
DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test03/input.xml"));
owners.load();
@@ -196,6 +195,12 @@ public class OwnersTest extends DpmTestBase {
owners.getProfileOwnerComponent(11));
assertEquals("1", owners.getProfileOwnerName(11));
assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
}
// Then re-read and check.
@@ -218,9 +223,19 @@ public class OwnersTest extends DpmTestBase {
owners.getProfileOwnerComponent(11));
assertEquals("1", owners.getProfileOwnerName(11));
assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
}
}
/**
* Note this also tests {@link Owners#setDeviceOwnerUserRestrictionsMigrated()}
* and {@link Owners#setProfileOwnerUserRestrictionsMigrated(int)}.
*/
public void testUpgrade04() throws Exception {
getContext().addUsers(10, 11, 20, 21);
@@ -228,8 +243,8 @@ public class OwnersTest extends DpmTestBase {
{
final OwnersTestable owners = new OwnersTestable(getContext());
createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
readAsset("OwnersTest/test04/input.xml"));
DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test04/input.xml"));
owners.load();
@@ -262,6 +277,12 @@ public class OwnersTest extends DpmTestBase {
owners.getProfileOwnerComponent(11));
assertEquals("1", owners.getProfileOwnerName(11));
assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
}
// Then re-read and check.
@@ -288,6 +309,40 @@ public class OwnersTest extends DpmTestBase {
owners.getProfileOwnerComponent(11));
assertEquals("1", owners.getProfileOwnerName(11));
assertEquals("com.google.android.testdpc1", owners.getProfileOwnerPackage(11));
assertTrue(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
owners.setDeviceOwnerUserRestrictionsMigrated();
}
{
final OwnersTestable owners = new OwnersTestable(getContext());
owners.load();
assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
owners.setProfileOwnerUserRestrictionsMigrated(11);
}
{
final OwnersTestable owners = new OwnersTestable(getContext());
owners.load();
assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertTrue(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
owners.setProfileOwnerUserRestrictionsMigrated(11);
}
}
@@ -298,8 +353,8 @@ public class OwnersTest extends DpmTestBase {
{
final OwnersTestable owners = new OwnersTestable(getContext());
createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
readAsset("OwnersTest/test05/input.xml"));
DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test05/input.xml"));
owners.load();
@@ -319,6 +374,12 @@ public class OwnersTest extends DpmTestBase {
assertNull(owners.getSystemUpdatePolicy());
assertEquals(0, owners.getProfileOwnerKeys().size());
assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
}
// Then re-read and check.
@@ -332,6 +393,12 @@ public class OwnersTest extends DpmTestBase {
assertNull(owners.getSystemUpdatePolicy());
assertEquals(0, owners.getProfileOwnerKeys().size());
assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
}
}
@@ -342,8 +409,8 @@ public class OwnersTest extends DpmTestBase {
{
final OwnersTestable owners = new OwnersTestable(getContext());
createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
readAsset("OwnersTest/test06/input.xml"));
DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test06/input.xml"));
owners.load();
@@ -362,6 +429,12 @@ public class OwnersTest extends DpmTestBase {
assertNotNull(owners.getSystemUpdatePolicy());
assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType());
assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
}
// Then re-read and check.
@@ -375,6 +448,12 @@ public class OwnersTest extends DpmTestBase {
assertNotNull(owners.getSystemUpdatePolicy());
assertEquals(5, owners.getSystemUpdatePolicy().getPolicyType());
assertFalse(owners.getDeviceOwnerUserRestrictionsNeedsMigration());
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(10));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(11));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(20));
assertFalse(owners.getProfileOwnerUserRestrictionsNeedsMigration(21));
}
}
@@ -384,8 +463,8 @@ public class OwnersTest extends DpmTestBase {
final OwnersTestable owners = new OwnersTestable(getContext());
// First, migrate to create new-style config files.
createLegacyFile(owners.getLegacyConfigFileWithTestOverride(),
readAsset("OwnersTest/test04/input.xml"));
DpmTestUtils.writeToFile(owners.getLegacyConfigFileWithTestOverride(),
DpmTestUtils.readAsset(mRealTestContext, "OwnersTest/test04/input.xml"));
owners.load();

View File

@@ -211,11 +211,14 @@ public class UserManagerTest extends AndroidTestCase {
public void testRestrictions() {
UserInfo testUser = createUser("User 1", 0);
Bundle restrictions = new Bundle();
restrictions.putBoolean(UserManager.DISALLOW_INSTALL_APPS, true);
restrictions.putBoolean(UserManager.DISALLOW_CONFIG_WIFI, false);
mUserManager.setUserRestrictions(restrictions, new UserHandle(testUser.id));
mUserManager.setUserRestriction(
UserManager.DISALLOW_INSTALL_APPS, true, new UserHandle(testUser.id));
mUserManager.setUserRestriction(
UserManager.DISALLOW_CONFIG_WIFI, false, new UserHandle(testUser.id));
Bundle stored = mUserManager.getUserRestrictions(new UserHandle(testUser.id));
// Note this will fail if DO already sets those restrictions.
assertEquals(stored.getBoolean(UserManager.DISALLOW_CONFIG_WIFI), false);
assertEquals(stored.getBoolean(UserManager.DISALLOW_UNINSTALL_APPS), false);
assertEquals(stored.getBoolean(UserManager.DISALLOW_INSTALL_APPS), true);