OSDN Git Service

Create Work Challenge per-user condition
authorClara Bayarri <clarabayarri@google.com>
Fri, 18 Dec 2015 16:29:18 +0000 (16:29 +0000)
committerClara Bayarri <clarabayarri@google.com>
Wed, 13 Jan 2016 10:27:12 +0000 (10:27 +0000)
Change the current static condition to a per-user condition so we
can check and enable/disable the work challenge properly. Also add
an isAllowed API, as the Work Challenge can only be used when the
user's DPC targets N or above to maintain backwards compatibility.

Change-Id: I0cb8b475838816801868ffb24726407aa257b4de

core/java/android/app/admin/DevicePolicyManager.java
core/java/android/app/admin/IDevicePolicyManager.aidl
core/java/com/android/internal/widget/LockPatternUtils.java
packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
services/core/java/com/android/server/LockSettingsService.java
services/core/java/com/android/server/LockSettingsStorage.java
services/core/java/com/android/server/am/UserController.java
services/core/java/com/android/server/pm/UserManagerService.java
services/core/java/com/android/server/trust/TrustManagerService.java
services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java

index 4de3ceb..bd0635d 100644 (file)
@@ -941,6 +941,22 @@ public class DevicePolicyManager {
     }
 
     /**
+     * Returns true if the Profile Challenge is available to use for the given profile user.
+     *
+     * @hide
+     */
+    public boolean isSeparateProfileChallengeAllowed(int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.isSeparateProfileChallengeAllowed(userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return false;
+    }
+
+    /**
      * Constant for {@link #setPasswordQuality}: the policy has no requirements
      * for the password.  Note that quality constants are ordered so that higher
      * values are more restrictive.
index d3c32c5..995ce00 100644 (file)
@@ -256,4 +256,6 @@ interface IDevicePolicyManager {
 
     String getShortSupportMessageForUser(in ComponentName admin, int userHandle);
     String getLongSupportMessageForUser(in ComponentName admin, int userHandle);
+
+    boolean isSeparateProfileChallengeAllowed(int userHandle);
 }
index e38d82f..89cb5b4 100644 (file)
@@ -24,6 +24,7 @@ import android.app.trust.TrustManager;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.pm.UserInfo;
 import android.os.AsyncTask;
 import android.os.Handler;
 import android.os.IBinder;
@@ -34,6 +35,7 @@ import android.os.ServiceManager;
 import android.os.SystemClock;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.os.storage.IMountService;
 import android.os.storage.StorageManager;
 import android.provider.Settings;
@@ -135,6 +137,8 @@ public class LockPatternUtils {
 
     private static final String ENABLED_TRUST_AGENTS = "lockscreen.enabledtrustagents";
 
+    private static final String SEPARATE_PROFILE_CHALLENGE_KEY = "lockscreen.profilechallenge";
+
     // Maximum allowed number of repeated or ordered characters in a sequence before we'll
     // consider it a complex PIN/password.
     public static final int MAX_ALLOWED_SEQUENCE = 3;
@@ -143,6 +147,7 @@ public class LockPatternUtils {
     private final ContentResolver mContentResolver;
     private DevicePolicyManager mDevicePolicyManager;
     private ILockSettings mLockSettingsService;
+    private UserManager mUserManager;
 
 
     public static final class RequestThrottledException extends Exception {
@@ -173,6 +178,13 @@ public class LockPatternUtils {
         return mDevicePolicyManager;
     }
 
+    private UserManager getUserManager() {
+        if (mUserManager == null) {
+            mUserManager = UserManager.get(mContext);
+        }
+        return mUserManager;
+    }
+
     private TrustManager getTrustManager() {
         TrustManager trust = (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
         if (trust == null) {
@@ -866,6 +878,39 @@ public class LockPatternUtils {
     }
 
     /**
+     * Enables/disables the Separate Profile Challenge for this {@param userHandle}. This is a no-op
+     * for user handles that do not belong to a managed profile.
+     */
+    public void setSeparateProfileChallengeEnabled(int userHandle, boolean enabled) {
+        UserInfo info = getUserManager().getUserInfo(userHandle);
+        if (info.isManagedProfile()) {
+            setBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, enabled, userHandle);
+        }
+    }
+
+    /**
+     * Retrieves whether the Separate Profile Challenge is enabled for this {@param userHandle}.
+     */
+    public boolean isSeparateProfileChallengeEnabled(int userHandle) {
+        UserInfo info = getUserManager().getUserInfo(userHandle);
+        if (!info.isManagedProfile()) {
+            return false;
+        }
+        return getBoolean(SEPARATE_PROFILE_CHALLENGE_KEY, false, userHandle);
+    }
+
+    /**
+     * Retrieves whether the current DPM allows use of the Profile Challenge.
+     */
+    public boolean isSeparateProfileChallengeAllowed(int userHandle) {
+        UserInfo info = getUserManager().getUserInfo(userHandle);
+        if (!info.isManagedProfile()) {
+            return false;
+        }
+        return getDevicePolicyManager().isSeparateProfileChallengeAllowed(userHandle);
+    }
+
+    /**
      * Deserialize a pattern.
      * @param string The pattern serialized with {@link #patternToString}
      * @return The pattern.
@@ -1288,10 +1333,6 @@ public class LockPatternUtils {
         }
     }
 
-    public static boolean isSeparateWorkChallengeEnabled() {
-        return StorageManager.isFileBasedEncryptionEnabled();
-    }
-
     public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
         try {
             getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
index 7556c6b..ed29a8f 100644 (file)
@@ -744,8 +744,7 @@ public class KeyguardViewMediator extends SystemUI {
 
         long timeout;
 
-        UserInfo user = UserManager.get(mContext).getUserInfo(userId);
-        if ((!user.isManagedProfile() && LockPatternUtils.isSeparateWorkChallengeEnabled())
+        if ((mLockPatternUtils.isSeparateProfileChallengeEnabled(userId))
                 || policyTimeout <= 0) {
             timeout = lockAfterTimeout;
         } else {
@@ -785,9 +784,9 @@ public class KeyguardViewMediator extends SystemUI {
     private void doKeyguardLaterLockedForChildProfiles() {
         UserManager um = UserManager.get(mContext);
         List<UserInfo> profiles = um.getEnabledProfiles(UserHandle.myUserId());
-        if (LockPatternUtils.isSeparateWorkChallengeEnabled() && profiles.size() > 1) {
+        if (profiles.size() > 1) {
             for (UserInfo info : profiles) {
-                if (info.id != UserHandle.myUserId() && info.isManagedProfile()) {
+                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(info.id)) {
                     long userTimeout = getLockTimeout(info.id);
                     long userWhen = SystemClock.elapsedRealtime() + userTimeout;
                     Intent lockIntent = new Intent(DELAYED_LOCK_PROFILE_ACTION);
index 1a21f5c..377d52f 100644 (file)
@@ -695,7 +695,7 @@ public class LockSettingsService extends ILockSettings.Stub {
             unlockUser(userId, token);
 
             UserInfo info = UserManager.get(mContext).getUserInfo(userId);
-            if (LockPatternUtils.isSeparateWorkChallengeEnabled() && info.isManagedProfile()) {
+            if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
                 TrustManager trustManager =
                         (TrustManager) mContext.getSystemService(Context.TRUST_SERVICE);
                 trustManager.setDeviceLockedForUser(userId, false);
index 137fa27..816c791 100644 (file)
@@ -71,6 +71,7 @@ class LockSettingsStorage {
     private final Object mFileWriteLock = new Object();
 
     private int mStoredCredentialType;
+    private LockPatternUtils mLockPatternUtils;
 
     class CredentialHash {
         static final int TYPE_NONE = -1;
@@ -100,6 +101,7 @@ class LockSettingsStorage {
     public LockSettingsStorage(Context context, Callback callback) {
         mContext = context;
         mOpenHelper = new DatabaseHelper(context, callback);
+        mLockPatternUtils = new LockPatternUtils(context);
     }
 
     public void writeKeyValue(String key, String value, int userId) {
@@ -388,7 +390,7 @@ class LockSettingsStorage {
 
     private int getUserParentOrSelfId(int userId) {
         // Device supports per user encryption, so lock is applied to the given user.
-        if (LockPatternUtils.isSeparateWorkChallengeEnabled()) {
+        if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
             return userId;
         }
         // Device uses Block Based Encryption, and the parent user's lock is used for the whole
index 7172859..56757ca 100644 (file)
@@ -143,6 +143,8 @@ final class UserController {
 
     private volatile UserManagerService mUserManager;
 
+    private final LockPatternUtils mLockPatternUtils;
+
     UserController(ActivityManagerService service) {
         mService = service;
         mHandler = mService.mHandler;
@@ -150,6 +152,7 @@ final class UserController {
         final UserState uss = new UserState(UserHandle.SYSTEM);
         mStartedUsers.put(UserHandle.USER_SYSTEM, uss);
         mUserLru.add(UserHandle.USER_SYSTEM);
+        mLockPatternUtils = new LockPatternUtils(mService.mContext);
         updateStartedUserArrayLocked();
     }
 
@@ -1294,13 +1297,12 @@ final class UserController {
      * intercept activity launches for work apps when the Work Challenge is present.
      */
     boolean shouldConfirmCredentials(int userId) {
-        final UserInfo user = getUserInfo(userId);
-        if (!user.isManagedProfile() || !LockPatternUtils.isSeparateWorkChallengeEnabled()) {
+        if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
             return false;
         }
         final KeyguardManager km = (KeyguardManager) mService.mContext
                 .getSystemService(KEYGUARD_SERVICE);
-        return km.isDeviceLocked(user.id);
+        return km.isDeviceLocked(userId);
     }
 
     void dump(PrintWriter pw, boolean dumpAll) {
index 3d614a3..ce6b369 100644 (file)
@@ -276,6 +276,8 @@ public class UserManagerService extends IUserManager.Stub {
     private final ArrayList<UserRestrictionsListener> mUserRestrictionsListeners =
             new ArrayList<>();
 
+    private final LockPatternUtils mLockPatternUtils;
+
     private static UserManagerService sInstance;
 
     public static UserManagerService getInstance() {
@@ -320,6 +322,7 @@ public class UserManagerService extends IUserManager.Stub {
         }
         mLocalService = new LocalService();
         LocalServices.addService(UserManagerInternal.class, mLocalService);
+        mLockPatternUtils = new LockPatternUtils(mContext);
     }
 
     void systemReady() {
@@ -456,7 +459,7 @@ public class UserManagerService extends IUserManager.Stub {
     @Override
     public int getCredentialOwnerProfile(int userHandle) {
         checkManageUsersPermission("get the credential owner");
-        if (!LockPatternUtils.isSeparateWorkChallengeEnabled()) {
+        if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) {
             synchronized (mUsersLock) {
                 UserInfo profileParent = getProfileParentLU(userHandle);
                 if (profileParent != null) {
index d888c56..78e3f7f 100644 (file)
@@ -290,14 +290,9 @@ public class TrustManagerService extends SystemService {
     }
 
     public void setDeviceLockedForUser(int userId, boolean locked) {
-        if (LockPatternUtils.isSeparateWorkChallengeEnabled()) {
-            UserInfo info = mUserManager.getUserInfo(userId);
-            if (info.isManagedProfile()) {
-                synchronized (mDeviceLockedForUser) {
-                    mDeviceLockedForUser.put(userId, locked);
-                }
-            } else {
-                Log.wtf(TAG, "Requested to change lock state for non-profile user " + userId);
+        if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
+            synchronized (mDeviceLockedForUser) {
+                mDeviceLockedForUser.put(userId, locked);
             }
         }
     }
@@ -669,7 +664,7 @@ public class TrustManagerService extends SystemService {
         public boolean isDeviceLocked(int userId) throws RemoteException {
             userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
                     false /* allowAll */, true /* requireFull */, "isDeviceLocked", null);
-            if (!LockPatternUtils.isSeparateWorkChallengeEnabled()) {
+            if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
                 userId = resolveProfileParent(userId);
             }
 
@@ -680,13 +675,13 @@ public class TrustManagerService extends SystemService {
         public boolean isDeviceSecure(int userId) throws RemoteException {
             userId = ActivityManager.handleIncomingUser(getCallingPid(), getCallingUid(), userId,
                     false /* allowAll */, true /* requireFull */, "isDeviceSecure", null);
-            if (!LockPatternUtils.isSeparateWorkChallengeEnabled()) {
+            if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userId)) {
                 userId = resolveProfileParent(userId);
             }
 
             long token = Binder.clearCallingIdentity();
             try {
-                return new LockPatternUtils(mContext).isSecure(userId);
+                return mLockPatternUtils.isSecure(userId);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
index 380763a..c4d5c50 100644 (file)
@@ -254,6 +254,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
     final IPackageManager mIPackageManager;
     final UserManager mUserManager;
     final UserManagerInternal mUserManagerInternal;
+    private final LockPatternUtils mLockPatternUtils;
 
     final LocalService mLocalService;
 
@@ -1329,6 +1330,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
         mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
 
         mLocalService = new LocalService();
+        mLockPatternUtils = new LockPatternUtils(mContext);
 
         mHasFeature = mContext.getPackageManager()
                 .hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
@@ -2573,10 +2575,16 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
         }
     }
 
-    private boolean isAdminApiLevelPreN(@NonNull ComponentName who, int userHandle) {
+    private boolean isAdminApiLevelMOrBelow(@NonNull ComponentName who, int userHandle) {
         DeviceAdminInfo adminInfo = findAdmin(who, userHandle, false);
         return adminInfo.getActivityInfo().applicationInfo.targetSdkVersion
-                < Build.VERSION_CODES.N;
+                <= Build.VERSION_CODES.M;
+    }
+
+    @Override
+    public boolean isSeparateProfileChallengeAllowed(int userHandle) {
+        ComponentName profileOwner = getProfileOwner(userHandle);
+        return !isAdminApiLevelMOrBelow(profileOwner, userHandle);
     }
 
     @Override
@@ -2618,7 +2626,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                 return admin != null ? admin.passwordQuality : mode;
             }
 
-            if (LockPatternUtils.isSeparateWorkChallengeEnabled() && !parent) {
+            if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle) && !parent) {
                 // If a Work Challenge is in use, only return its restrictions.
                 DevicePolicyData policy = getUserDataUnchecked(userHandle);
                 final int N = policy.mAdminList.size();
@@ -2638,7 +2646,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                     // Only aggregate data for the parent profile plus the non-work challenge
                     // enabled profiles.
                     if (!(userInfo.isManagedProfile()
-                            && LockPatternUtils.isSeparateWorkChallengeEnabled())) {
+                            && mLockPatternUtils.isSeparateProfileChallengeEnabled(userInfo.id))) {
                         DevicePolicyData policy = getUserDataUnchecked(userInfo.id);
                         final int N = policy.mAdminList.size();
                         for (int i = 0; i < N; i++) {
@@ -3224,8 +3232,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                     getActiveAdminForCallerLocked(null, DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             ComponentName adminComponentName = admin.info.getComponent();
             // TODO: Include the Admin sdk level check in LockPatternUtils check.
-            ComponentName who = !isAdminApiLevelPreN(adminComponentName, userHandle)
-                    && LockPatternUtils.isSeparateWorkChallengeEnabled()
+            ComponentName who = !isAdminApiLevelMOrBelow(adminComponentName, userHandle)
+                    && mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)
                         ? adminComponentName : null;
             if (policy.mActivePasswordQuality < getPasswordQuality(who, userHandle, parent)
                     || policy.mActivePasswordLength < getPasswordMinimumLength(null, userHandle)) {
@@ -4028,7 +4036,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
         }
         enforceFullCrossUsersPermission(userHandle);
         // Managed Profile password can only be changed when per user encryption is present.
-        if (!LockPatternUtils.isSeparateWorkChallengeEnabled()) {
+        if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) {
             enforceNotManagedProfile(userHandle, "set the active password");
         }
 
@@ -4055,7 +4063,7 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                 setExpirationAlarmCheckLocked(mContext, policy);
 
                 // Send a broadcast to each profile using this password as its primary unlock.
-                if (LockPatternUtils.isSeparateWorkChallengeEnabled()) {
+                if (mLockPatternUtils.isSeparateProfileChallengeEnabled(userHandle)) {
                     sendAdminCommandLocked(
                             DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
                             DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
@@ -4647,10 +4655,9 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
 
                 UserInfo user = mUserManager.getUserInfo(userHandle);
                 final List<UserInfo> profiles;
-                if (user.isManagedProfile() || LockPatternUtils.isSeparateWorkChallengeEnabled()) {
-                    // If we are being asked about a managed profile or the main user profile has a
-                    // separate lock from the work profile, just return keyguard features disabled
-                    // by admins in the profile.
+                if (user.isManagedProfile()) {
+                    // If we are being asked about a managed profile, just return keyguard features
+                    // disabled by admins in the profile.
                     profiles = Collections.singletonList(user);
                 } else {
                     // Otherwise return those set by admins in the user
@@ -4669,9 +4676,11 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
                             // If we are being asked explictly about this user
                             // return all disabled features even if its a managed profile.
                             which |= admin.disabledKeyguardFeatures;
-                        } else {
+                        } else if (!mLockPatternUtils.isSeparateProfileChallengeEnabled(
+                                userInfo.id)) {
                             // Otherwise a managed profile is only allowed to disable
-                            // some features on the parent user.
+                            // some features on the parent user, and we only aggregate them if
+                            // it doesn't have its own challenge.
                             which |= (admin.disabledKeyguardFeatures
                                     & PROFILE_KEYGUARD_FEATURES_AFFECT_OWNER);
                         }