diff options
Diffstat (limited to 'services')
3 files changed, 604 insertions, 384 deletions
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java index 28a4310..aec5d6e 100644 --- a/services/java/com/android/server/DevicePolicyManagerService.java +++ b/services/java/com/android/server/DevicePolicyManagerService.java @@ -16,7 +16,6 @@ package com.android.server; -import com.android.internal.content.PackageMonitor; import com.android.internal.os.storage.ExternalStorageFormatter; import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.JournaledFile; @@ -28,7 +27,9 @@ import org.xmlpull.v1.XmlPullParserException; import org.xmlpull.v1.XmlSerializer; import android.app.Activity; +import android.app.ActivityManagerNative; import android.app.AlarmManager; +import android.app.AppGlobals; import android.app.PendingIntent; import android.app.admin.DeviceAdminInfo; import android.app.admin.DeviceAdminReceiver; @@ -40,6 +41,7 @@ import android.content.ContentResolver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; +import android.content.pm.IPackageManager; import android.content.pm.PackageManager; import android.content.pm.PackageManager.NameNotFoundException; import android.content.pm.ResolveInfo; @@ -49,6 +51,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.IPowerManager; import android.os.PowerManager; +import android.os.Process; import android.os.RecoverySystem; import android.os.RemoteCallback; import android.os.RemoteException; @@ -56,10 +59,12 @@ import android.os.ServiceManager; import android.os.SystemClock; import android.os.SystemProperties; import android.os.UserHandle; +import android.os.UserManager; import android.provider.Settings; import android.util.PrintWriterPrinter; import android.util.Printer; import android.util.Slog; +import android.util.SparseArray; import android.util.Xml; import android.view.IWindowManager; import android.view.WindowManagerPolicy; @@ -82,56 +87,86 @@ import java.util.Set; * Implementation of the device policy APIs. */ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + private static final String DEVICE_POLICIES_XML = "device_policies.xml"; + private static final String TAG = "DevicePolicyManagerService"; private static final int REQUEST_EXPIRE_PASSWORD = 5571; - private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * 86400 * 1000; // 5 days, in ms + private static final long MS_PER_DAY = 86400 * 1000; + + private static final long EXPIRATION_GRACE_PERIOD_MS = 5 * MS_PER_DAY; // 5 days, in ms protected static final String ACTION_EXPIRED_PASSWORD_NOTIFICATION = "com.android.server.ACTION_EXPIRED_PASSWORD_NOTIFICATION"; - private static final long MS_PER_DAY = 86400 * 1000; + private static final boolean DBG = false; final Context mContext; - final MyPackageMonitor mMonitor; final PowerManager.WakeLock mWakeLock; IPowerManager mIPowerManager; IWindowManager mIWindowManager; - int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; - int mActivePasswordLength = 0; - int mActivePasswordUpperCase = 0; - int mActivePasswordLowerCase = 0; - int mActivePasswordLetters = 0; - int mActivePasswordNumeric = 0; - int mActivePasswordSymbols = 0; - int mActivePasswordNonLetter = 0; - int mFailedPasswordAttempts = 0; - - int mPasswordOwner = -1; - Handler mHandler = new Handler(); + public static class DevicePolicyData { + int mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; + int mActivePasswordLength = 0; + int mActivePasswordUpperCase = 0; + int mActivePasswordLowerCase = 0; + int mActivePasswordLetters = 0; + int mActivePasswordNumeric = 0; + int mActivePasswordSymbols = 0; + int mActivePasswordNonLetter = 0; + int mFailedPasswordAttempts = 0; + + int mUserHandle;; + int mPasswordOwner = -1; + long mLastMaximumTimeToLock = -1; + + final HashMap<ComponentName, ActiveAdmin> mAdminMap + = new HashMap<ComponentName, ActiveAdmin>(); + final ArrayList<ActiveAdmin> mAdminList + = new ArrayList<ActiveAdmin>(); + + public DevicePolicyData(int userHandle) { + mUserHandle = userHandle; + } + } - long mLastMaximumTimeToLock = -1; + final SparseArray<DevicePolicyData> mUserData = new SparseArray<DevicePolicyData>(); - final HashMap<ComponentName, ActiveAdmin> mAdminMap - = new HashMap<ComponentName, ActiveAdmin>(); - final ArrayList<ActiveAdmin> mAdminList - = new ArrayList<ActiveAdmin>(); + Handler mHandler = new Handler(); BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - String action = intent.getAction(); + final String action = intent.getAction(); + final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, + getSendingUserId()); if (Intent.ACTION_BOOT_COMPLETED.equals(action) || ACTION_EXPIRED_PASSWORD_NOTIFICATION.equals(action)) { - Slog.v(TAG, "Sending password expiration notifications for action " + action); + Slog.v(TAG, "Sending password expiration notifications for action " + action + + " for user " + userHandle); mHandler.post(new Runnable() { public void run() { - handlePasswordExpirationNotification(); + handlePasswordExpirationNotification(getUserData(userHandle)); } }); + } else if (Intent.ACTION_USER_REMOVED.equals(action)) { + removeUserData(userHandle); + } else if (Intent.ACTION_USER_STARTED.equals(action) + || Intent.ACTION_PACKAGE_CHANGED.equals(action) + || Intent.ACTION_PACKAGE_REMOVED.equals(action) + || Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) { + + if (Intent.ACTION_USER_STARTED.equals(action)) { + // Reset the policy data + synchronized (DevicePolicyManagerService.this) { + mUserData.remove(userHandle); + } + } + + handlePackagesChanged(userHandle); } } }; @@ -194,6 +229,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { int getUid() { return info.getActivityInfo().applicationInfo.uid; } + public UserHandle getUserHandle() { + return new UserHandle(UserHandle.getUserId(info.getActivityInfo().applicationInfo.uid)); + } + void writeToXml(XmlSerializer out) throws IllegalArgumentException, IllegalStateException, IOException { out.startTag(null, "policies"); @@ -421,39 +460,28 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - class MyPackageMonitor extends PackageMonitor { - @Override - public void onSomePackagesChanged() { - synchronized (DevicePolicyManagerService.this) { - boolean removed = false; - for (int i=mAdminList.size()-1; i>=0; i--) { - ActiveAdmin aa = mAdminList.get(i); - int change = isPackageDisappearing(aa.info.getPackageName()); - if (change == PACKAGE_PERMANENT_CHANGE - || change == PACKAGE_TEMPORARY_CHANGE) { - Slog.w(TAG, "Admin unexpectedly uninstalled: " - + aa.info.getComponent()); - removed = true; - mAdminList.remove(i); - } else if (isPackageModified(aa.info.getPackageName())) { - try { - mContext.getPackageManager().getReceiverInfo( - aa.info.getComponent(), 0); - } catch (NameNotFoundException e) { - Slog.w(TAG, "Admin package change removed component: " - + aa.info.getComponent()); - removed = true; - mAdminList.remove(i); - } - } - } - if (removed) { - validatePasswordOwnerLocked(); - syncDeviceCapabilitiesLocked(); - saveSettingsLocked(); + private void handlePackagesChanged(int userHandle) { + boolean removed = false; + Slog.d(TAG, "Handling package changes for user " + userHandle); + DevicePolicyData policy = getUserData(userHandle); + IPackageManager pm = AppGlobals.getPackageManager(); + for (int i = policy.mAdminList.size() - 1; i >= 0; i--) { + ActiveAdmin aa = policy.mAdminList.get(i); + try { + if (pm.getPackageInfo(aa.info.getPackageName(), 0, userHandle) == null + || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle) == null) { + removed = true; + policy.mAdminList.remove(i); } + } catch (RemoteException re) { + // Shouldn't happen } } + if (removed) { + validatePasswordOwnerLocked(policy); + syncDeviceCapabilitiesLocked(policy); + saveSettingsLocked(policy.mUserHandle); + } } /** @@ -461,22 +489,62 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { */ public DevicePolicyManagerService(Context context) { mContext = context; - mMonitor = new MyPackageMonitor(); - mMonitor.register(context, null, true); mWakeLock = ((PowerManager)context.getSystemService(Context.POWER_SERVICE)) .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM"); IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_BOOT_COMPLETED); filter.addAction(ACTION_EXPIRED_PASSWORD_NOTIFICATION); - context.registerReceiver(mReceiver, filter); + filter.addAction(Intent.ACTION_USER_REMOVED); + filter.addAction(Intent.ACTION_USER_STARTED); + context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler); + filter = new IntentFilter(); + filter.addAction(Intent.ACTION_PACKAGE_CHANGED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); + filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE); + filter.addDataScheme("package"); + context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler); + } + + /** + * Creates and loads the policy data from xml. + * @param userHandle the user for whom to load the policy data + * @return + */ + DevicePolicyData getUserData(int userHandle) { + synchronized (this) { + DevicePolicyData policy = mUserData.get(userHandle); + if (policy == null) { + policy = new DevicePolicyData(userHandle); + mUserData.append(userHandle, policy); + loadSettingsLocked(policy, userHandle); + } + return policy; + } + } + + void removeUserData(int userHandle) { + synchronized (this) { + if (userHandle == UserHandle.USER_OWNER) { + Slog.w(TAG, "Tried to remove device policy file for user 0! Ignoring."); + return; + } + DevicePolicyData policy = mUserData.get(userHandle); + if (policy != null) { + mUserData.remove(userHandle); + } + File policyFile = new File(Environment.getUserSystemDirectory(userHandle), + DEVICE_POLICIES_XML); + policyFile.delete(); + Slog.i(TAG, "Removed device policy file " + policyFile.getAbsolutePath()); + } } /** * Set an alarm for an upcoming event - expiration warning, expiration, or post-expiration * reminders. Clears alarm if no expirations are configured. */ - protected void setExpirationAlarmCheckLocked(Context context) { - final long expiration = getPasswordExpirationLocked(null); + protected void setExpirationAlarmCheckLocked(Context context, DevicePolicyData policy) { + final long expiration = getPasswordExpirationLocked(null, policy.mUserHandle); final long now = System.currentTimeMillis(); final long timeToExpire = expiration - now; final long alarmTime; @@ -499,9 +567,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long token = Binder.clearCallingIdentity(); try { AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); - PendingIntent pi = PendingIntent.getBroadcast(context, REQUEST_EXPIRE_PASSWORD, + PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD, new Intent(ACTION_EXPIRED_PASSWORD_NOTIFICATION), - PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT); + PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT, + new UserHandle(policy.mUserHandle)); am.cancel(pi); if (alarmTime != 0) { am.set(AlarmManager.RTC, alarmTime, pi); @@ -527,8 +596,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return mIWindowManager; } - ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who) { - ActiveAdmin admin = mAdminMap.get(who); + ActiveAdmin getActiveAdminUncheckedLocked(ComponentName who, int userHandle) { + ActiveAdmin admin = getUserData(userHandle).mAdminMap.get(who); if (admin != null && who.getPackageName().equals(admin.info.getActivityInfo().packageName) && who.getClassName().equals(admin.info.getActivityInfo().name)) { @@ -540,8 +609,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy) throws SecurityException { final int callingUid = Binder.getCallingUid(); + final int userHandle = UserHandle.getUserId(callingUid); + final DevicePolicyData policy = getUserData(userHandle); if (who != null) { - ActiveAdmin admin = mAdminMap.get(who); + ActiveAdmin admin = policy.mAdminMap.get(who); if (admin == null) { throw new SecurityException("No active admin " + who); } @@ -556,9 +627,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } return admin; } else { - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (admin.getUid() == callingUid && admin.info.usesPolicy(reqPolicy)) { return admin; } @@ -579,18 +650,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { intent.putExtra("expiration", admin.passwordExpirationDate); } if (result != null) { - mContext.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER, + mContext.sendOrderedBroadcastAsUser(intent, admin.getUserHandle(), null, result, mHandler, Activity.RESULT_OK, null, null); } else { mContext.sendBroadcastAsUser(intent, UserHandle.OWNER); } } - void sendAdminCommandLocked(String action, int reqPolicy) { - final int N = mAdminList.size(); - if (N > 0) { - for (int i=0; i<N; i++) { - ActiveAdmin admin = mAdminList.get(i); + void sendAdminCommandLocked(String action, int reqPolicy, int userHandle) { + final DevicePolicyData policy = getUserData(userHandle); + final int count = policy.mAdminList.size(); + if (count > 0) { + for (int i = 0; i < count; i++) { + ActiveAdmin admin = policy.mAdminList.get(i); if (admin.info.usesPolicy(reqPolicy)) { sendAdminCommandLocked(admin, action); } @@ -598,8 +670,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - void removeActiveAdminLocked(final ComponentName adminReceiver) { - final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver); + void removeActiveAdminLocked(final ComponentName adminReceiver, int userHandle) { + final ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle); if (admin != null) { sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED, @@ -607,28 +679,31 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { @Override public void onReceive(Context context, Intent intent) { synchronized (DevicePolicyManagerService.this) { + int userHandle = admin.getUserHandle().getIdentifier(); + DevicePolicyData policy = getUserData(userHandle); boolean doProxyCleanup = admin.info.usesPolicy( DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY); - mAdminList.remove(admin); - mAdminMap.remove(adminReceiver); - validatePasswordOwnerLocked(); - syncDeviceCapabilitiesLocked(); + policy.mAdminList.remove(admin); + policy.mAdminMap.remove(adminReceiver); + validatePasswordOwnerLocked(policy); + syncDeviceCapabilitiesLocked(policy); if (doProxyCleanup) { - resetGlobalProxyLocked(); + resetGlobalProxyLocked(getUserData(userHandle)); } - saveSettingsLocked(); - updateMaximumTimeToLockLocked(); + saveSettingsLocked(userHandle); + updateMaximumTimeToLockLocked(policy); } } }); } } - public DeviceAdminInfo findAdmin(ComponentName adminName) { + public DeviceAdminInfo findAdmin(ComponentName adminName, int userHandle) { + enforceCrossUserPermission(userHandle); Intent resolveIntent = new Intent(); resolveIntent.setComponent(adminName); List<ResolveInfo> infos = mContext.getPackageManager().queryBroadcastReceivers( - resolveIntent, PackageManager.GET_META_DATA); + resolveIntent, PackageManager.GET_META_DATA, userHandle); if (infos == null || infos.size() <= 0) { throw new IllegalArgumentException("Unknown admin: " + adminName); } @@ -636,21 +711,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { try { return new DeviceAdminInfo(mContext, infos.get(0)); } catch (XmlPullParserException e) { - Slog.w(TAG, "Bad device admin requested: " + adminName, e); + Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e); return null; } catch (IOException e) { - Slog.w(TAG, "Bad device admin requested: " + adminName, e); + Slog.w(TAG, "Bad device admin requested for user=" + userHandle + ": " + adminName, e); return null; } } - private static JournaledFile makeJournaledFile() { - final String base = "/data/system/device_policies.xml"; + private static JournaledFile makeJournaledFile(int userHandle) { + final String base = userHandle == 0 + ? "/data/system/" + DEVICE_POLICIES_XML + : new File(Environment.getUserSystemDirectory(userHandle), DEVICE_POLICIES_XML) + .getAbsolutePath(); return new JournaledFile(new File(base), new File(base + ".tmp")); } - private void saveSettingsLocked() { - JournaledFile journal = makeJournaledFile(); + private void saveSettingsLocked(int userHandle) { + DevicePolicyData policy = getUserData(userHandle); + JournaledFile journal = makeJournaledFile(userHandle); FileOutputStream stream = null; try { stream = new FileOutputStream(journal.chooseForWrite(), false); @@ -660,9 +739,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.startTag(null, "policies"); - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { - ActiveAdmin ap = mAdminList.get(i); + ActiveAdmin ap = policy.mAdminList.get(i); if (ap != null) { out.startTag(null, "admin"); out.attribute(null, "name", ap.info.getComponent().flattenToString()); @@ -671,32 +750,32 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - if (mPasswordOwner >= 0) { + if (policy.mPasswordOwner >= 0) { out.startTag(null, "password-owner"); - out.attribute(null, "value", Integer.toString(mPasswordOwner)); + out.attribute(null, "value", Integer.toString(policy.mPasswordOwner)); out.endTag(null, "password-owner"); } - if (mFailedPasswordAttempts != 0) { + if (policy.mFailedPasswordAttempts != 0) { out.startTag(null, "failed-password-attempts"); - out.attribute(null, "value", Integer.toString(mFailedPasswordAttempts)); + out.attribute(null, "value", Integer.toString(policy.mFailedPasswordAttempts)); out.endTag(null, "failed-password-attempts"); } - if (mActivePasswordQuality != 0 || mActivePasswordLength != 0 - || mActivePasswordUpperCase != 0 || mActivePasswordLowerCase != 0 - || mActivePasswordLetters != 0 || mActivePasswordNumeric != 0 - || mActivePasswordSymbols != 0 || mActivePasswordNonLetter != 0) { + if (policy.mActivePasswordQuality != 0 || policy.mActivePasswordLength != 0 + || policy.mActivePasswordUpperCase != 0 || policy.mActivePasswordLowerCase != 0 + || policy.mActivePasswordLetters != 0 || policy.mActivePasswordNumeric != 0 + || policy.mActivePasswordSymbols != 0 || policy.mActivePasswordNonLetter != 0) { out.startTag(null, "active-password"); - out.attribute(null, "quality", Integer.toString(mActivePasswordQuality)); - out.attribute(null, "length", Integer.toString(mActivePasswordLength)); - out.attribute(null, "uppercase", Integer.toString(mActivePasswordUpperCase)); - out.attribute(null, "lowercase", Integer.toString(mActivePasswordLowerCase)); - out.attribute(null, "letters", Integer.toString(mActivePasswordLetters)); + out.attribute(null, "quality", Integer.toString(policy.mActivePasswordQuality)); + out.attribute(null, "length", Integer.toString(policy.mActivePasswordLength)); + out.attribute(null, "uppercase", Integer.toString(policy.mActivePasswordUpperCase)); + out.attribute(null, "lowercase", Integer.toString(policy.mActivePasswordLowerCase)); + out.attribute(null, "letters", Integer.toString(policy.mActivePasswordLetters)); out.attribute(null, "numeric", Integer - .toString(mActivePasswordNumeric)); - out.attribute(null, "symbols", Integer.toString(mActivePasswordSymbols)); - out.attribute(null, "nonletter", Integer.toString(mActivePasswordNonLetter)); + .toString(policy.mActivePasswordNumeric)); + out.attribute(null, "symbols", Integer.toString(policy.mActivePasswordSymbols)); + out.attribute(null, "nonletter", Integer.toString(policy.mActivePasswordNonLetter)); out.endTag(null, "active-password"); } @@ -705,7 +784,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { out.endDocument(); stream.close(); journal.commit(); - sendChangedNotification(); + sendChangedNotification(userHandle); } catch (IOException e) { try { if (stream != null) { @@ -718,20 +797,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - private void sendChangedNotification() { + private void sendChangedNotification(int userHandle) { Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED); intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); long ident = Binder.clearCallingIdentity(); try { - // TODO: This shouldn't be sent to all users, if DPM is per user. - mContext.sendBroadcastAsUser(intent, UserHandle.ALL); + mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle)); } finally { Binder.restoreCallingIdentity(ident); } } - private void loadSettingsLocked() { - JournaledFile journal = makeJournaledFile(); + private void loadSettingsLocked(DevicePolicyData policy, int userHandle) { + JournaledFile journal = makeJournaledFile(userHandle); FileInputStream stream = null; File file = journal.chooseForRead(); try { @@ -760,40 +838,46 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { String name = parser.getAttributeValue(null, "name"); try { DeviceAdminInfo dai = findAdmin( - ComponentName.unflattenFromString(name)); + ComponentName.unflattenFromString(name), userHandle); + if (DBG && (UserHandle.getUserId(dai.getActivityInfo().applicationInfo.uid) + != userHandle)) { + Slog.w(TAG, "findAdmin returned an incorrect uid " + + dai.getActivityInfo().applicationInfo.uid + " for user " + + userHandle); + } if (dai != null) { ActiveAdmin ap = new ActiveAdmin(dai); ap.readFromXml(parser); - mAdminMap.put(ap.info.getComponent(), ap); - mAdminList.add(ap); + policy.mAdminMap.put(ap.info.getComponent(), ap); + policy.mAdminList.add(ap); } } catch (RuntimeException e) { Slog.w(TAG, "Failed loading admin " + name, e); } } else if ("failed-password-attempts".equals(tag)) { - mFailedPasswordAttempts = Integer.parseInt( + policy.mFailedPasswordAttempts = Integer.parseInt( parser.getAttributeValue(null, "value")); XmlUtils.skipCurrentTag(parser); } else if ("password-owner".equals(tag)) { - mPasswordOwner = Integer.parseInt( + policy.mPasswordOwner = Integer.parseInt( parser.getAttributeValue(null, "value")); XmlUtils.skipCurrentTag(parser); } else if ("active-password".equals(tag)) { - mActivePasswordQuality = Integer.parseInt( + policy.mActivePasswordQuality = Integer.parseInt( parser.getAttributeValue(null, "quality")); - mActivePasswordLength = Integer.parseInt( + policy.mActivePasswordLength = Integer.parseInt( parser.getAttributeValue(null, "length")); - mActivePasswordUpperCase = Integer.parseInt( + policy.mActivePasswordUpperCase = Integer.parseInt( parser.getAttributeValue(null, "uppercase")); - mActivePasswordLowerCase = Integer.parseInt( + policy.mActivePasswordLowerCase = Integer.parseInt( parser.getAttributeValue(null, "lowercase")); - mActivePasswordLetters = Integer.parseInt( + policy.mActivePasswordLetters = Integer.parseInt( parser.getAttributeValue(null, "letters")); - mActivePasswordNumeric = Integer.parseInt( + policy.mActivePasswordNumeric = Integer.parseInt( parser.getAttributeValue(null, "numeric")); - mActivePasswordSymbols = Integer.parseInt( + policy.mActivePasswordSymbols = Integer.parseInt( parser.getAttributeValue(null, "symbols")); - mActivePasswordNonLetter = Integer.parseInt( + policy.mActivePasswordNonLetter = Integer.parseInt( parser.getAttributeValue(null, "nonletter")); XmlUtils.skipCurrentTag(parser); } else { @@ -827,24 +911,24 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // a sanity check in case the two get out of sync; this should // never normally happen. LockPatternUtils utils = new LockPatternUtils(mContext); - if (utils.getActivePasswordQuality() < mActivePasswordQuality) { + if (utils.getActivePasswordQuality() < policy.mActivePasswordQuality) { Slog.w(TAG, "Active password quality 0x" - + Integer.toHexString(mActivePasswordQuality) + + Integer.toHexString(policy.mActivePasswordQuality) + " does not match actual quality 0x" + Integer.toHexString(utils.getActivePasswordQuality())); - mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; - mActivePasswordLength = 0; - mActivePasswordUpperCase = 0; - mActivePasswordLowerCase = 0; - mActivePasswordLetters = 0; - mActivePasswordNumeric = 0; - mActivePasswordSymbols = 0; - mActivePasswordNonLetter = 0; + policy.mActivePasswordQuality = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; + policy.mActivePasswordLength = 0; + policy.mActivePasswordUpperCase = 0; + policy.mActivePasswordLowerCase = 0; + policy.mActivePasswordLetters = 0; + policy.mActivePasswordNumeric = 0; + policy.mActivePasswordSymbols = 0; + policy.mActivePasswordNonLetter = 0; } - validatePasswordOwnerLocked(); - syncDeviceCapabilitiesLocked(); - updateMaximumTimeToLockLocked(); + validatePasswordOwnerLocked(policy); + syncDeviceCapabilitiesLocked(policy); + updateMaximumTimeToLockLocked(policy); } static void validateQualityConstant(int quality) { @@ -862,19 +946,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + Integer.toHexString(quality)); } - void validatePasswordOwnerLocked() { - if (mPasswordOwner >= 0) { + void validatePasswordOwnerLocked(DevicePolicyData policy) { + if (policy.mPasswordOwner >= 0) { boolean haveOwner = false; - for (int i=mAdminList.size()-1; i>=0; i--) { - if (mAdminList.get(i).getUid() == mPasswordOwner) { + for (int i = policy.mAdminList.size() - 1; i >= 0; i--) { + if (policy.mAdminList.get(i).getUid() == policy.mPasswordOwner) { haveOwner = true; break; } } if (!haveOwner) { - Slog.w(TAG, "Previous password owner " + mPasswordOwner + Slog.w(TAG, "Previous password owner " + policy.mPasswordOwner + " no longer active; disabling"); - mPasswordOwner = -1; + policy.mPasswordOwner = -1; } } } @@ -883,11 +967,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Pushes down policy information to the system for any policies related to general device * capabilities that need to be enforced by lower level services (e.g. Camera services). */ - void syncDeviceCapabilitiesLocked() { + void syncDeviceCapabilitiesLocked(DevicePolicyData policy) { // Ensure the status of the camera is synced down to the system. Interested native services // should monitor this value and act accordingly. boolean systemState = SystemProperties.getBoolean(SYSTEM_PROP_DISABLE_CAMERA, false); - boolean cameraDisabled = getCameraDisabled(null); + boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle); if (cameraDisabled != systemState) { long token = Binder.clearCallingIdentity(); try { @@ -903,19 +987,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { public void systemReady() { synchronized (this) { - loadSettingsLocked(); + loadSettingsLocked(getUserData(UserHandle.USER_OWNER), UserHandle.USER_OWNER); } } - private void handlePasswordExpirationNotification() { + private void handlePasswordExpirationNotification(DevicePolicyData policy) { synchronized (this) { final long now = System.currentTimeMillis(); - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); if (N <= 0) { return; } for (int i=0; i < N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD) && admin.passwordExpirationTimeout > 0L && admin.passwordExpirationDate > 0L @@ -923,7 +1007,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { sendAdminCommandLocked(admin, DeviceAdminReceiver.ACTION_PASSWORD_EXPIRING); } } - setExpirationAlarmCheckLocked(mContext); + setExpirationAlarmCheckLocked(mContext, policy); } } @@ -931,27 +1015,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * @param adminReceiver The admin to add * @param refreshing true = update an active admin, no error */ - public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing) { + public void setActiveAdmin(ComponentName adminReceiver, boolean refreshing, int userHandle) { mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); + enforceCrossUserPermission(userHandle); - DeviceAdminInfo info = findAdmin(adminReceiver); + DevicePolicyData policy = getUserData(userHandle); + DeviceAdminInfo info = findAdmin(adminReceiver, userHandle); if (info == null) { throw new IllegalArgumentException("Bad admin: " + adminReceiver); } synchronized (this) { long ident = Binder.clearCallingIdentity(); try { - if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver) != null) { + if (!refreshing && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) { throw new IllegalArgumentException("Admin is already added"); } ActiveAdmin newAdmin = new ActiveAdmin(info); - mAdminMap.put(adminReceiver, newAdmin); + policy.mAdminMap.put(adminReceiver, newAdmin); int replaceIndex = -1; if (refreshing) { - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i=0; i < N; i++) { - ActiveAdmin oldAdmin = mAdminList.get(i); + ActiveAdmin oldAdmin = policy.mAdminList.get(i); if (oldAdmin.info.getComponent().equals(adminReceiver)) { replaceIndex = i; break; @@ -959,11 +1045,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } if (replaceIndex == -1) { - mAdminList.add(newAdmin); + policy.mAdminList.add(newAdmin); } else { - mAdminList.set(replaceIndex, newAdmin); + policy.mAdminList.set(replaceIndex, newAdmin); } - saveSettingsLocked(); + saveSettingsLocked(userHandle); sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED); } finally { Binder.restoreCallingIdentity(ident); @@ -971,15 +1057,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public boolean isAdminActive(ComponentName adminReceiver) { + public boolean isAdminActive(ComponentName adminReceiver, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { - return getActiveAdminUncheckedLocked(adminReceiver) != null; + return getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null; } } - public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId) { + public boolean hasGrantedPolicy(ComponentName adminReceiver, int policyId, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { - ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver); + ActiveAdmin administrator = getActiveAdminUncheckedLocked(adminReceiver, userHandle); if (administrator == null) { throw new SecurityException("No active admin " + adminReceiver); } @@ -987,25 +1075,29 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public List<ComponentName> getActiveAdmins() { + public List<ComponentName> getActiveAdmins(int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); if (N <= 0) { return null; } ArrayList<ComponentName> res = new ArrayList<ComponentName>(N); for (int i=0; i<N; i++) { - res.add(mAdminList.get(i).info.getComponent()); + res.add(policy.mAdminList.get(i).info.getComponent()); } return res; } } - public boolean packageHasActiveAdmins(String packageName) { + public boolean packageHasActiveAdmins(String packageName, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { - if (mAdminList.get(i).info.getPackageName().equals(packageName)) { + if (policy.mAdminList.get(i).info.getPackageName().equals(packageName)) { return true; } } @@ -1013,9 +1105,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void removeActiveAdmin(ComponentName adminReceiver) { + public void removeActiveAdmin(ComponentName adminReceiver, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver); + ActiveAdmin admin = getActiveAdminUncheckedLocked(adminReceiver, userHandle); if (admin == null) { return; } @@ -1025,15 +1118,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } long ident = Binder.clearCallingIdentity(); try { - removeActiveAdminLocked(adminReceiver); + removeActiveAdminLocked(adminReceiver, userHandle); } finally { Binder.restoreCallingIdentity(ident); } } } - public void setPasswordQuality(ComponentName who, int quality) { + public void setPasswordQuality(ComponentName who, int quality, int userHandle) { validateQualityConstant(quality); + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { @@ -1043,23 +1137,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.passwordQuality != quality) { ap.passwordQuality = quality; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } } } - public int getPasswordQuality(ComponentName who) { + public int getPasswordQuality(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { int mode = DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED; + DevicePolicyData policy = getUserData(userHandle); if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.passwordQuality : mode; } - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (mode < admin.passwordQuality) { mode = admin.passwordQuality; } @@ -1068,7 +1164,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordMinimumLength(ComponentName who, int length) { + public void setPasswordMinimumLength(ComponentName who, int length, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -1077,23 +1174,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordLength != length) { ap.minimumPasswordLength = length; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } } } - public int getPasswordMinimumLength(ComponentName who) { + public int getPasswordMinimumLength(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { + DevicePolicyData policy = getUserData(userHandle); int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.minimumPasswordLength : length; } - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (length < admin.minimumPasswordLength) { length = admin.minimumPasswordLength; } @@ -1102,7 +1201,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordHistoryLength(ComponentName who, int length) { + public void setPasswordHistoryLength(ComponentName who, int length, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -1111,23 +1211,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.passwordHistoryLength != length) { ap.passwordHistoryLength = length; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } } } - public int getPasswordHistoryLength(ComponentName who) { + public int getPasswordHistoryLength(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { + DevicePolicyData policy = getUserData(userHandle); int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.passwordHistoryLength : length; } - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (length < admin.passwordHistoryLength) { length = admin.passwordHistoryLength; } @@ -1136,7 +1238,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordExpirationTimeout(ComponentName who, long timeout) { + public void setPasswordExpirationTimeout(ComponentName who, long timeout, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -1155,8 +1258,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT) .format(new Date(expiration))); } - saveSettingsLocked(); - setExpirationAlarmCheckLocked(mContext); // in case this is the first one + saveSettingsLocked(userHandle); + // in case this is the first one + setExpirationAlarmCheckLocked(mContext, getUserData(userHandle)); } } @@ -1164,17 +1268,19 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Return a single admin's expiration cycle time, or the min of all cycle times. * Returns 0 if not configured. */ - public long getPasswordExpirationTimeout(ComponentName who) { + public long getPasswordExpirationTimeout(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.passwordExpirationTimeout : 0L; } long timeout = 0L; - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (timeout == 0L || (admin.passwordExpirationTimeout != 0L && timeout > admin.passwordExpirationTimeout)) { timeout = admin.passwordExpirationTimeout; @@ -1188,16 +1294,17 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Return a single admin's expiration date/time, or the min (soonest) for all admins. * Returns 0 if not configured. */ - private long getPasswordExpirationLocked(ComponentName who) { + private long getPasswordExpirationLocked(ComponentName who, int userHandle) { if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.passwordExpirationDate : 0L; } long timeout = 0L; - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (timeout == 0L || (admin.passwordExpirationDate != 0 && timeout > admin.passwordExpirationDate)) { timeout = admin.passwordExpirationDate; @@ -1206,13 +1313,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return timeout; } - public long getPasswordExpiration(ComponentName who) { + public long getPasswordExpiration(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { - return getPasswordExpirationLocked(who); + return getPasswordExpirationLocked(who, userHandle); } } - public void setPasswordMinimumUpperCase(ComponentName who, int length) { + public void setPasswordMinimumUpperCase(ComponentName who, int length, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -1221,23 +1330,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordUpperCase != length) { ap.minimumPasswordUpperCase = length; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } } } - public int getPasswordMinimumUpperCase(ComponentName who) { + public int getPasswordMinimumUpperCase(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.minimumPasswordUpperCase : length; } - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (length < admin.minimumPasswordUpperCase) { length = admin.minimumPasswordUpperCase; } @@ -1246,7 +1357,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordMinimumLowerCase(ComponentName who, int length) { + public void setPasswordMinimumLowerCase(ComponentName who, int length, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -1255,23 +1367,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordLowerCase != length) { ap.minimumPasswordLowerCase = length; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } } } - public int getPasswordMinimumLowerCase(ComponentName who) { + public int getPasswordMinimumLowerCase(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.minimumPasswordLowerCase : length; } - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (length < admin.minimumPasswordLowerCase) { length = admin.minimumPasswordLowerCase; } @@ -1280,7 +1394,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordMinimumLetters(ComponentName who, int length) { + public void setPasswordMinimumLetters(ComponentName who, int length, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -1289,23 +1404,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordLetters != length) { ap.minimumPasswordLetters = length; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } } } - public int getPasswordMinimumLetters(ComponentName who) { + public int getPasswordMinimumLetters(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.minimumPasswordLetters : length; } - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (length < admin.minimumPasswordLetters) { length = admin.minimumPasswordLetters; } @@ -1314,7 +1431,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordMinimumNumeric(ComponentName who, int length) { + public void setPasswordMinimumNumeric(ComponentName who, int length, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -1323,23 +1441,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordNumeric != length) { ap.minimumPasswordNumeric = length; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } } } - public int getPasswordMinimumNumeric(ComponentName who) { + public int getPasswordMinimumNumeric(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.minimumPasswordNumeric : length; } - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (length < admin.minimumPasswordNumeric) { length = admin.minimumPasswordNumeric; } @@ -1348,7 +1468,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordMinimumSymbols(ComponentName who, int length) { + public void setPasswordMinimumSymbols(ComponentName who, int length, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -1357,23 +1478,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordSymbols != length) { ap.minimumPasswordSymbols = length; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } } } - public int getPasswordMinimumSymbols(ComponentName who) { + public int getPasswordMinimumSymbols(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.minimumPasswordSymbols : length; } - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (length < admin.minimumPasswordSymbols) { length = admin.minimumPasswordSymbols; } @@ -1382,7 +1505,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void setPasswordMinimumNonLetter(ComponentName who, int length) { + public void setPasswordMinimumNonLetter(ComponentName who, int length, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -1391,23 +1515,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); if (ap.minimumPasswordNonLetter != length) { ap.minimumPasswordNonLetter = length; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } } } - public int getPasswordMinimumNonLetter(ComponentName who) { + public int getPasswordMinimumNonLetter(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { int length = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.minimumPasswordNonLetter : length; } - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (length < admin.minimumPasswordNonLetter) { length = admin.minimumPasswordNonLetter; } @@ -1416,39 +1542,43 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public boolean isActivePasswordSufficient() { + public boolean isActivePasswordSufficient(int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { + DevicePolicyData policy = getUserData(userHandle); // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); - if (mActivePasswordQuality < getPasswordQuality(null) - || mActivePasswordLength < getPasswordMinimumLength(null)) { + if (policy.mActivePasswordQuality < getPasswordQuality(null, userHandle) + || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) { return false; } - if(mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) { + if (policy.mActivePasswordQuality != DevicePolicyManager.PASSWORD_QUALITY_COMPLEX) { return true; } - return mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null) - && mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null) - && mActivePasswordLetters >= getPasswordMinimumLetters(null) - && mActivePasswordNumeric >= getPasswordMinimumNumeric(null) - && mActivePasswordSymbols >= getPasswordMinimumSymbols(null) - && mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null); + return policy.mActivePasswordUpperCase >= getPasswordMinimumUpperCase(null, userHandle) + && policy.mActivePasswordLowerCase >= getPasswordMinimumLowerCase(null, userHandle) + && policy.mActivePasswordLetters >= getPasswordMinimumLetters(null, userHandle) + && policy.mActivePasswordNumeric >= getPasswordMinimumNumeric(null, userHandle) + && policy.mActivePasswordSymbols >= getPasswordMinimumSymbols(null, userHandle) + && policy.mActivePasswordNonLetter >= getPasswordMinimumNonLetter(null, userHandle); } } - public int getCurrentFailedPasswordAttempts() { + public int getCurrentFailedPasswordAttempts(int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); - return mFailedPasswordAttempts; + return getUserData(userHandle).mFailedPasswordAttempts; } } - public void setMaximumFailedPasswordsForWipe(ComponentName who, int num) { + public void setMaximumFailedPasswordsForWipe(ComponentName who, int num, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. @@ -1458,23 +1588,25 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); if (ap.maximumFailedPasswordsForWipe != num) { ap.maximumFailedPasswordsForWipe = num; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } } } - public int getMaximumFailedPasswordsForWipe(ComponentName who) { + public int getMaximumFailedPasswordsForWipe(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { + DevicePolicyData policy = getUserData(userHandle); int count = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.maximumFailedPasswordsForWipe : count; } - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (count == 0) { count = admin.maximumFailedPasswordsForWipe; } else if (admin.maximumFailedPasswordsForWipe != 0 @@ -1486,14 +1618,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public boolean resetPassword(String password, int flags) { + public boolean resetPassword(String password, int flags, int userHandle) { + enforceCrossUserPermission(userHandle); int quality; synchronized (this) { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_RESET_PASSWORD); - quality = getPasswordQuality(null); + quality = getPasswordQuality(null, userHandle); if (quality != DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED) { int realQuality = LockPatternUtils.computePasswordQuality(password); if (realQuality < quality @@ -1506,7 +1639,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } quality = Math.max(realQuality, quality); } - int length = getPasswordMinimumLength(null); + int length = getPasswordMinimumLength(null, userHandle); if (password.length() < length) { Slog.w(TAG, "resetPassword: password length " + password.length() + " does not meet required length " + length); @@ -1535,13 +1668,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { nonletter++; } } - int neededLetters = getPasswordMinimumLetters(null); + int neededLetters = getPasswordMinimumLetters(null, userHandle); if(letters < neededLetters) { Slog.w(TAG, "resetPassword: number of letters " + letters + " does not meet required number of letters " + neededLetters); return false; } - int neededNumbers = getPasswordMinimumNumeric(null); + int neededNumbers = getPasswordMinimumNumeric(null, userHandle); if (numbers < neededNumbers) { Slog .w(TAG, "resetPassword: number of numerical digits " + numbers @@ -1549,27 +1682,27 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { + neededNumbers); return false; } - int neededLowerCase = getPasswordMinimumLowerCase(null); + int neededLowerCase = getPasswordMinimumLowerCase(null, userHandle); if (lowercase < neededLowerCase) { Slog.w(TAG, "resetPassword: number of lowercase letters " + lowercase + " does not meet required number of lowercase letters " + neededLowerCase); return false; } - int neededUpperCase = getPasswordMinimumUpperCase(null); + int neededUpperCase = getPasswordMinimumUpperCase(null, userHandle); if (uppercase < neededUpperCase) { Slog.w(TAG, "resetPassword: number of uppercase letters " + uppercase + " does not meet required number of uppercase letters " + neededUpperCase); return false; } - int neededSymbols = getPasswordMinimumSymbols(null); + int neededSymbols = getPasswordMinimumSymbols(null, userHandle); if (symbols < neededSymbols) { Slog.w(TAG, "resetPassword: number of special symbols " + symbols + " does not meet required number of special symbols " + neededSymbols); return false; } - int neededNonLetter = getPasswordMinimumNonLetter(null); + int neededNonLetter = getPasswordMinimumNonLetter(null, userHandle); if (nonletter < neededNonLetter) { Slog.w(TAG, "resetPassword: number of non-letter characters " + nonletter + " does not meet required number of non-letter characters " @@ -1580,7 +1713,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } int callingUid = Binder.getCallingUid(); - if (mPasswordOwner >= 0 && mPasswordOwner != callingUid) { + DevicePolicyData policy = getUserData(userHandle); + if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) { Slog.w(TAG, "resetPassword: already set by another uid and not entered by user"); return false; } @@ -1590,13 +1724,13 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { long ident = Binder.clearCallingIdentity(); try { LockPatternUtils utils = new LockPatternUtils(mContext); - utils.saveLockPassword(password, quality); + utils.saveLockPassword(password, quality, false, userHandle); synchronized (this) { int newOwner = (flags&DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0 ? callingUid : -1; - if (mPasswordOwner != newOwner) { - mPasswordOwner = newOwner; - saveSettingsLocked(); + if (policy.mPasswordOwner != newOwner) { + policy.mPasswordOwner = newOwner; + saveSettingsLocked(userHandle); } } } finally { @@ -1606,7 +1740,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return true; } - public void setMaximumTimeToLock(ComponentName who, long timeMs) { + public void setMaximumTimeToLock(ComponentName who, long timeMs, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -1615,15 +1750,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_FORCE_LOCK); if (ap.maximumTimeToUnlock != timeMs) { ap.maximumTimeToUnlock = timeMs; - saveSettingsLocked(); - updateMaximumTimeToLockLocked(); + saveSettingsLocked(userHandle); + updateMaximumTimeToLockLocked(getUserData(userHandle)); } } } - void updateMaximumTimeToLockLocked() { - long timeMs = getMaximumTimeToLock(null); - if (mLastMaximumTimeToLock == timeMs) { + void updateMaximumTimeToLockLocked(DevicePolicyData policy) { + long timeMs = getMaximumTimeToLock(null, policy.mUserHandle); + if (policy.mLastMaximumTimeToLock == timeMs) { return; } @@ -1638,7 +1773,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { Settings.Global.STAY_ON_WHILE_PLUGGED_IN, 0); } - mLastMaximumTimeToLock = timeMs; + policy.mLastMaximumTimeToLock = timeMs; try { getIPowerManager().setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs); @@ -1650,18 +1785,20 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public long getMaximumTimeToLock(ComponentName who) { + public long getMaximumTimeToLock(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { long time = 0; if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return admin != null ? admin.maximumTimeToUnlock : time; } - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); for (int i=0; i<N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (time == 0) { time = admin.maximumTimeToUnlock; } else if (admin.maximumTimeToUnlock != 0 @@ -1679,17 +1816,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // so try to retrieve it to check that the caller is one. getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_FORCE_LOCK); - long ident = Binder.clearCallingIdentity(); - try { - // Power off the display - getIPowerManager().goToSleep(SystemClock.uptimeMillis(), - PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN); - // Ensure the device is locked - getWindowManager().lockNow(); - } catch (RemoteException e) { - } finally { - Binder.restoreCallingIdentity(ident); - } + lockNowUnchecked(); + } + } + + private void lockNowUnchecked() { + long ident = Binder.clearCallingIdentity(); + try { + // Power off the display + getIPowerManager().goToSleep(SystemClock.uptimeMillis(), + PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN); + // Ensure the device is locked + getWindowManager().lockNow(); + } catch (RemoteException e) { + } finally { + Binder.restoreCallingIdentity(ident); } } @@ -1719,7 +1860,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } } - public void wipeData(int flags) { + public void wipeData(int flags, final int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { // This API can only be called by an active device admin, // so try to retrieve it to check that the caller is one. @@ -1727,19 +1869,35 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_WIPE_DATA); long ident = Binder.clearCallingIdentity(); try { - wipeDataLocked(flags); + if (userHandle == UserHandle.USER_OWNER) { + wipeDataLocked(flags); + } else { + lockNowUnchecked(); + mHandler.post(new Runnable() { + public void run() { + try { + ActivityManagerNative.getDefault().switchUser(0); + ((UserManager) mContext.getSystemService(Context.USER_SERVICE)) + .removeUser(userHandle); + } catch (RemoteException re) { + // Shouldn't happen + } + } + }); + } } finally { Binder.restoreCallingIdentity(ident); } } } - public void getRemoveWarning(ComponentName comp, final RemoteCallback result) { + public void getRemoveWarning(ComponentName comp, final RemoteCallback result, int userHandle) { + enforceCrossUserPermission(userHandle); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); synchronized (this) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(comp); + ActiveAdmin admin = getActiveAdminUncheckedLocked(comp, userHandle); if (admin == null) { try { result.sendResult(null); @@ -1749,7 +1907,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } Intent intent = new Intent(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLE_REQUESTED); intent.setComponent(admin.info.getComponent()); - mContext.sendOrderedBroadcastAsUser(intent, UserHandle.OWNER, + mContext.sendOrderedBroadcastAsUser(intent, new UserHandle(userHandle), null, new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { @@ -1763,34 +1921,36 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } public void setActivePasswordState(int quality, int length, int letters, int uppercase, - int lowercase, int numbers, int symbols, int nonletter) { + int lowercase, int numbers, int symbols, int nonletter, int userHandle) { + enforceCrossUserPermission(userHandle); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); + DevicePolicyData p = getUserData(userHandle); validateQualityConstant(quality); synchronized (this) { - if (mActivePasswordQuality != quality || mActivePasswordLength != length - || mFailedPasswordAttempts != 0 || mActivePasswordLetters != letters - || mActivePasswordUpperCase != uppercase - || mActivePasswordLowerCase != lowercase || mActivePasswordNumeric != numbers - || mActivePasswordSymbols != symbols || mActivePasswordNonLetter != nonletter) { + if (p.mActivePasswordQuality != quality || p.mActivePasswordLength != length + || p.mFailedPasswordAttempts != 0 || p.mActivePasswordLetters != letters + || p.mActivePasswordUpperCase != uppercase + || p.mActivePasswordLowerCase != lowercase || p.mActivePasswordNumeric != numbers + || p.mActivePasswordSymbols != symbols || p.mActivePasswordNonLetter != nonletter) { long ident = Binder.clearCallingIdentity(); try { - mActivePasswordQuality = quality; - mActivePasswordLength = length; - mActivePasswordLetters = letters; - mActivePasswordLowerCase = lowercase; - mActivePasswordUpperCase = uppercase; - mActivePasswordNumeric = numbers; - mActivePasswordSymbols = symbols; - mActivePasswordNonLetter = nonletter; - mFailedPasswordAttempts = 0; - saveSettingsLocked(); - updatePasswordExpirationsLocked(); - setExpirationAlarmCheckLocked(mContext); + p.mActivePasswordQuality = quality; + p.mActivePasswordLength = length; + p.mActivePasswordLetters = letters; + p.mActivePasswordLowerCase = lowercase; + p.mActivePasswordUpperCase = uppercase; + p.mActivePasswordNumeric = numbers; + p.mActivePasswordSymbols = symbols; + p.mActivePasswordNonLetter = nonletter; + p.mFailedPasswordAttempts = 0; + saveSettingsLocked(userHandle); + updatePasswordExpirationsLocked(userHandle); + setExpirationAlarmCheckLocked(mContext, p); sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_CHANGED, - DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD); + DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle); } finally { Binder.restoreCallingIdentity(ident); } @@ -1801,55 +1961,60 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * Called any time the device password is updated. Resets all password expiration clocks. */ - private void updatePasswordExpirationsLocked() { - final int N = mAdminList.size(); + private void updatePasswordExpirationsLocked(int userHandle) { + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); if (N > 0) { for (int i=0; i<N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (admin.info.usesPolicy(DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD)) { long timeout = admin.passwordExpirationTimeout; long expiration = timeout > 0L ? (timeout + System.currentTimeMillis()) : 0L; admin.passwordExpirationDate = expiration; } } - saveSettingsLocked(); + saveSettingsLocked(userHandle); } } - public void reportFailedPasswordAttempt() { + public void reportFailedPasswordAttempt(int userHandle) { + enforceCrossUserPermission(userHandle); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); synchronized (this) { + DevicePolicyData policy = getUserData(userHandle); long ident = Binder.clearCallingIdentity(); try { - mFailedPasswordAttempts++; - saveSettingsLocked(); - int max = getMaximumFailedPasswordsForWipe(null); - if (max > 0 && mFailedPasswordAttempts >= max) { + policy.mFailedPasswordAttempts++; + saveSettingsLocked(userHandle); + int max = getMaximumFailedPasswordsForWipe(null, userHandle); + if (max > 0 && policy.mFailedPasswordAttempts >= max) { wipeDataLocked(0); } sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_FAILED, - DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); + DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle); } finally { Binder.restoreCallingIdentity(ident); } } } - public void reportSuccessfulPasswordAttempt() { + public void reportSuccessfulPasswordAttempt(int userHandle) { + enforceCrossUserPermission(userHandle); mContext.enforceCallingOrSelfPermission( android.Manifest.permission.BIND_DEVICE_ADMIN, null); synchronized (this) { - if (mFailedPasswordAttempts != 0 || mPasswordOwner >= 0) { + DevicePolicyData policy = getUserData(userHandle); + if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) { long ident = Binder.clearCallingIdentity(); try { - mFailedPasswordAttempts = 0; - mPasswordOwner = -1; - saveSettingsLocked(); + policy.mFailedPasswordAttempts = 0; + policy.mPasswordOwner = -1; + saveSettingsLocked(userHandle); sendAdminCommandLocked(DeviceAdminReceiver.ACTION_PASSWORD_SUCCEEDED, - DeviceAdminInfo.USES_POLICY_WATCH_LOGIN); + DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle); } finally { Binder.restoreCallingIdentity(ident); } @@ -1858,26 +2023,36 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { } public ComponentName setGlobalProxy(ComponentName who, String proxySpec, - String exclusionList) { + String exclusionList, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized(this) { if (who == null) { throw new NullPointerException("ComponentName is null"); } + // Only check if owner has set global proxy. We don't allow other users to set it. + DevicePolicyData policy = getUserData(UserHandle.USER_OWNER); ActiveAdmin admin = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_SETS_GLOBAL_PROXY); // Scan through active admins and find if anyone has already // set the global proxy. - Set<ComponentName> compSet = mAdminMap.keySet(); + Set<ComponentName> compSet = policy.mAdminMap.keySet(); for (ComponentName component : compSet) { - ActiveAdmin ap = mAdminMap.get(component); + ActiveAdmin ap = policy.mAdminMap.get(component); if ((ap.specifiesGlobalProxy) && (!component.equals(who))) { // Another admin already sets the global proxy // Return it to the caller. return component; } } + + // If the user is not the owner, don't set the global proxy. Fail silently. + if (UserHandle.getCallingUserId() != UserHandle.USER_OWNER) { + Slog.w(TAG, "Only the owner is allowed to set the global proxy. User " + + userHandle + " is not permitted."); + return null; + } if (proxySpec == null) { admin.specifiesGlobalProxy = false; admin.globalProxySpec = null; @@ -1892,19 +2067,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // Reset the global proxy accordingly // Do this using system permissions, as apps cannot write to secure settings long origId = Binder.clearCallingIdentity(); - resetGlobalProxyLocked(); + resetGlobalProxyLocked(policy); Binder.restoreCallingIdentity(origId); return null; } } - public ComponentName getGlobalProxyAdmin() { + public ComponentName getGlobalProxyAdmin(int userHandle) { + enforceCrossUserPermission(userHandle); synchronized(this) { + DevicePolicyData policy = getUserData(UserHandle.USER_OWNER); // Scan through active admins and find if anyone has already // set the global proxy. - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { - ActiveAdmin ap = mAdminList.get(i); + ActiveAdmin ap = policy.mAdminList.get(i); if (ap.specifiesGlobalProxy) { // Device admin sets the global proxy // Return it to the caller. @@ -1916,10 +2093,10 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { return null; } - private void resetGlobalProxyLocked() { - final int N = mAdminList.size(); + private void resetGlobalProxyLocked(DevicePolicyData policy) { + final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { - ActiveAdmin ap = mAdminList.get(i); + ActiveAdmin ap = policy.mAdminList.get(i); if (ap.specifiesGlobalProxy) { saveGlobalProxyLocked(ap.globalProxySpec, ap.globalProxyExclusionList); return; @@ -1957,12 +2134,21 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Set the storage encryption request for a single admin. Returns the new total request * status (for all admins). */ - public int setStorageEncryption(ComponentName who, boolean encrypt) { + public int setStorageEncryption(ComponentName who, boolean encrypt, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { // Check for permissions if (who == null) { throw new NullPointerException("ComponentName is null"); } + // Only owner can set storage encryption + if (userHandle != UserHandle.USER_OWNER + || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) { + Slog.w(TAG, "Only owner is allowed to set storage encryption. User " + + UserHandle.getCallingUserId() + " is not permitted."); + return 0; + } + ActiveAdmin ap = getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_ENCRYPTED_STORAGE); @@ -1974,14 +2160,15 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { // (1) Record the value for the admin so it's sticky if (ap.encryptionRequested != encrypt) { ap.encryptionRequested = encrypt; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } + DevicePolicyData policy = getUserData(UserHandle.USER_OWNER); // (2) Compute "max" for all admins boolean newRequested = false; - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { - newRequested |= mAdminList.get(i).encryptionRequested; + newRequested |= policy.mAdminList.get(i).encryptionRequested; } // Notify OS of new request @@ -1998,20 +2185,22 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Get the current storage encryption request status for a given admin, or aggregate of all * active admins. */ - public boolean getStorageEncryption(ComponentName who) { + public boolean getStorageEncryption(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { // Check for permissions if a particular caller is specified if (who != null) { // When checking for a single caller, status is based on caller's request - ActiveAdmin ap = getActiveAdminUncheckedLocked(who); + ActiveAdmin ap = getActiveAdminUncheckedLocked(who, userHandle); return ap != null ? ap.encryptionRequested : false; } // If no particular caller is specified, return the aggregate set of requests. // This is short circuited by returning true on the first hit. - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { - if (mAdminList.get(i).encryptionRequested) { + if (policy.mAdminList.get(i).encryptionRequested) { return true; } } @@ -2022,7 +2211,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * Get the current encryption status of the device. */ - public int getStorageEncryptionStatus() { + public int getStorageEncryptionStatus(int userHandle) { + enforceCrossUserPermission(userHandle); return getEncryptionStatus(); } @@ -2069,7 +2259,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * Disables all device cameras according to the specified admin. */ - public void setCameraDisabled(ComponentName who, boolean disabled) { + public void setCameraDisabled(ComponentName who, boolean disabled, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -2078,9 +2269,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA); if (ap.disableCamera != disabled) { ap.disableCamera = disabled; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } - syncDeviceCapabilitiesLocked(); + syncDeviceCapabilitiesLocked(getUserData(userHandle)); } } @@ -2088,17 +2279,18 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Gets whether or not all device cameras are disabled for a given admin, or disabled for any * active admins. */ - public boolean getCameraDisabled(ComponentName who) { + public boolean getCameraDisabled(ComponentName who, int userHandle) { synchronized (this) { if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return (admin != null) ? admin.disableCamera : false; } + DevicePolicyData policy = getUserData(userHandle); // Determine whether or not the device camera is disabled for any active admins. - final int N = mAdminList.size(); + final int N = policy.mAdminList.size(); for (int i = 0; i < N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); if (admin.disableCamera) { return true; } @@ -2110,7 +2302,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { /** * Selectively disable keyguard widgets. */ - public void setKeyguardWidgetsDisabled(ComponentName who, int which) { + public void setKeyguardWidgetsDisabled(ComponentName who, int which, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who == null) { throw new NullPointerException("ComponentName is null"); @@ -2119,9 +2312,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_WIDGETS); if ((ap.disableKeyguardWidgets & which) != which) { ap.disableKeyguardWidgets |= which; - saveSettingsLocked(); + saveSettingsLocked(userHandle); } - syncDeviceCapabilitiesLocked(); + syncDeviceCapabilitiesLocked(getUserData(userHandle)); } } @@ -2129,24 +2322,39 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { * Gets the disabled state for widgets in keyguard for the given admin, * or the aggregate of all active admins if who is null. */ - public int getKeyguardWidgetsDisabled(ComponentName who) { + public int getKeyguardWidgetsDisabled(ComponentName who, int userHandle) { + enforceCrossUserPermission(userHandle); synchronized (this) { if (who != null) { - ActiveAdmin admin = getActiveAdminUncheckedLocked(who); + ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle); return (admin != null) ? admin.disableKeyguardWidgets : 0; } // Determine whether or not keyguard widgets are disabled for any active admins. - final int N = mAdminList.size(); + DevicePolicyData policy = getUserData(userHandle); + final int N = policy.mAdminList.size(); int which = 0; for (int i = 0; i < N; i++) { - ActiveAdmin admin = mAdminList.get(i); + ActiveAdmin admin = policy.mAdminList.get(i); which |= admin.disableKeyguardWidgets; } return which; } } + private void enforceCrossUserPermission(int userHandle) { + if (userHandle < 0) { + throw new IllegalArgumentException("Invalid userId " + userHandle); + } + final int callingUid = Binder.getCallingUid(); + if (userHandle == UserHandle.getUserId(callingUid)) return; + if (callingUid != Process.SYSTEM_UID && callingUid != 0) { + mContext.enforceCallingOrSelfPermission( + android.Manifest.permission.INTERACT_ACROSS_USERS_FULL, "Must be system or have" + + " INTERACT_ACROSS_USERS_FULL permission"); + } + } + @Override protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) @@ -2163,19 +2371,23 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub { synchronized (this) { p.println("Current Device Policy Manager state:"); - p.println(" Enabled Device Admins:"); - final int N = mAdminList.size(); - for (int i=0; i<N; i++) { - ActiveAdmin ap = mAdminList.get(i); - if (ap != null) { - pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString()); - pw.println(":"); - ap.dump(" ", pw); + int userCount = mUserData.size(); + for (int u = 0; u < userCount; u++) { + DevicePolicyData policy = getUserData(mUserData.keyAt(u)); + p.println(" Enabled Device Admins (User " + policy.mUserHandle + "):"); + final int N = policy.mAdminList.size(); + for (int i=0; i<N; i++) { + ActiveAdmin ap = policy.mAdminList.get(i); + if (ap != null) { + pw.print(" "); pw.print(ap.info.getComponent().flattenToShortString()); + pw.println(":"); + ap.dump(" ", pw); + } } - } - pw.println(" "); - pw.print(" mPasswordOwner="); pw.println(mPasswordOwner); + pw.println(" "); + pw.print(" mPasswordOwner="); pw.println(policy.mPasswordOwner); + } } } } diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java index 536c612..f0cc083 100644 --- a/services/java/com/android/server/pm/PackageManagerService.java +++ b/services/java/com/android/server/pm/PackageManagerService.java @@ -8044,13 +8044,13 @@ public class PackageManagerService extends IPackageManager.Stub { IDevicePolicyManager dpm = IDevicePolicyManager.Stub.asInterface( ServiceManager.getService(Context.DEVICE_POLICY_SERVICE)); try { - if (dpm != null && dpm.packageHasActiveAdmins(packageName)) { + if (dpm != null && dpm.packageHasActiveAdmins(packageName, UserHandle.getUserId(uid))) { Slog.w(TAG, "Not removing package " + packageName + ": has active device admin"); return PackageManager.DELETE_FAILED_DEVICE_POLICY_MANAGER; } } catch (RemoteException e) { } - + synchronized (mInstallLock) { res = deletePackageLI(packageName, (flags & PackageManager.DELETE_ALL_USERS) != 0 diff --git a/services/java/com/android/server/wm/KeyguardDisableHandler.java b/services/java/com/android/server/wm/KeyguardDisableHandler.java index d935b8b..859df51 100644 --- a/services/java/com/android/server/wm/KeyguardDisableHandler.java +++ b/services/java/com/android/server/wm/KeyguardDisableHandler.java @@ -16,12 +16,15 @@ package com.android.server.wm; +import android.app.ActivityManagerNative; import android.app.admin.DevicePolicyManager; import android.content.Context; import android.os.Handler; import android.os.IBinder; import android.os.Message; +import android.os.RemoteException; import android.os.TokenWatcher; +import android.os.UserHandle; import android.util.Log; import android.util.Pair; import android.view.WindowManagerPolicy; @@ -87,9 +90,14 @@ public class KeyguardDisableHandler extends Handler { DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService( Context.DEVICE_POLICY_SERVICE); if (dpm != null) { - mAllowDisableKeyguard = dpm.getPasswordQuality(null) - == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ? - ALLOW_DISABLE_YES : ALLOW_DISABLE_NO; + try { + mAllowDisableKeyguard = dpm.getPasswordQuality(null, + ActivityManagerNative.getDefault().getCurrentUser().id) + == DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED ? + ALLOW_DISABLE_YES : ALLOW_DISABLE_NO; + } catch (RemoteException re) { + // Nothing much we can do + } } } if (mAllowDisableKeyguard == ALLOW_DISABLE_YES) { |