}
/**
+ * 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.
String getShortSupportMessageForUser(in ComponentName admin, int userHandle);
String getLongSupportMessageForUser(in ComponentName admin, int userHandle);
+
+ boolean isSeparateProfileChallengeAllowed(int userHandle);
}
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;
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;
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;
private final ContentResolver mContentResolver;
private DevicePolicyManager mDevicePolicyManager;
private ILockSettings mLockSettingsService;
+ private UserManager mUserManager;
public static final class RequestThrottledException extends Exception {
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) {
}
/**
+ * 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.
}
}
- public static boolean isSeparateWorkChallengeEnabled() {
- return StorageManager.isFileBasedEncryptionEnabled();
- }
-
public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
try {
getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
long timeout;
- UserInfo user = UserManager.get(mContext).getUserInfo(userId);
- if ((!user.isManagedProfile() && LockPatternUtils.isSeparateWorkChallengeEnabled())
+ if ((mLockPatternUtils.isSeparateProfileChallengeEnabled(userId))
|| policyTimeout <= 0) {
timeout = lockAfterTimeout;
} else {
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);
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);
private final Object mFileWriteLock = new Object();
private int mStoredCredentialType;
+ private LockPatternUtils mLockPatternUtils;
class CredentialHash {
static final int TYPE_NONE = -1;
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) {
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
private volatile UserManagerService mUserManager;
+ private final LockPatternUtils mLockPatternUtils;
+
UserController(ActivityManagerService service) {
mService = service;
mHandler = mService.mHandler;
final UserState uss = new UserState(UserHandle.SYSTEM);
mStartedUsers.put(UserHandle.USER_SYSTEM, uss);
mUserLru.add(UserHandle.USER_SYSTEM);
+ mLockPatternUtils = new LockPatternUtils(mService.mContext);
updateStartedUserArrayLocked();
}
* 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) {
private final ArrayList<UserRestrictionsListener> mUserRestrictionsListeners =
new ArrayList<>();
+ private final LockPatternUtils mLockPatternUtils;
+
private static UserManagerService sInstance;
public static UserManagerService getInstance() {
}
mLocalService = new LocalService();
LocalServices.addService(UserManagerInternal.class, mLocalService);
+ mLockPatternUtils = new LockPatternUtils(mContext);
}
void systemReady() {
@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) {
}
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);
}
}
}
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);
}
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);
}
final IPackageManager mIPackageManager;
final UserManager mUserManager;
final UserManagerInternal mUserManagerInternal;
+ private final LockPatternUtils mLockPatternUtils;
final LocalService mLocalService;
mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
mLocalService = new LocalService();
+ mLockPatternUtils = new LockPatternUtils(mContext);
mHasFeature = mContext.getPackageManager()
.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
}
}
- 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
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();
// 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++) {
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)) {
}
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");
}
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);
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
// 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);
}