Create Work Challenge per-user condition
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
This commit is contained in:
@@ -940,6 +940,22 @@ public class DevicePolicyManager {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -256,4 +256,6 @@ interface IDevicePolicyManager {
|
||||
|
||||
String getShortSupportMessageForUser(in ComponentName admin, int userHandle);
|
||||
String getLongSupportMessageForUser(in ComponentName admin, int userHandle);
|
||||
|
||||
boolean isSeparateProfileChallengeAllowed(int userHandle);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
@@ -865,6 +877,39 @@ public class LockPatternUtils {
|
||||
DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, userHandle);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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}
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user