summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Android.mk1
-rw-r--r--core/java/android/app/trust/IStrongAuthTracker.aidl26
-rw-r--r--core/java/android/app/trust/ITrustManager.aidl2
-rw-r--r--core/java/android/app/trust/TrustManager.java38
-rw-r--r--core/java/com/android/internal/widget/ILockSettings.aidl4
-rw-r--r--core/java/com/android/internal/widget/LockPatternUtils.java184
-rw-r--r--packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java32
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java2
-rw-r--r--services/core/java/com/android/server/LockSettingsService.java25
-rw-r--r--services/core/java/com/android/server/LockSettingsStrongAuth.java167
-rw-r--r--services/core/java/com/android/server/trust/TrustManagerService.java112
-rw-r--r--services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java8
12 files changed, 462 insertions, 139 deletions
diff --git a/Android.mk b/Android.mk
index 18d9c69..2a87fd2 100644
--- a/Android.mk
+++ b/Android.mk
@@ -90,6 +90,7 @@ LOCAL_SRC_FILES += \
core/java/android/app/IWallpaperManager.aidl \
core/java/android/app/IWallpaperManagerCallback.aidl \
core/java/android/app/admin/IDevicePolicyManager.aidl \
+ core/java/android/app/trust/IStrongAuthTracker.aidl \
core/java/android/app/trust/ITrustManager.aidl \
core/java/android/app/trust/ITrustListener.aidl \
core/java/android/app/backup/IBackupManager.aidl \
diff --git a/core/java/android/app/trust/IStrongAuthTracker.aidl b/core/java/android/app/trust/IStrongAuthTracker.aidl
new file mode 100644
index 0000000..36c71bf
--- /dev/null
+++ b/core/java/android/app/trust/IStrongAuthTracker.aidl
@@ -0,0 +1,26 @@
+/*
+**
+** Copyright 2015, The Android Open Source Project
+**
+** Licensed under the Apache License, Version 2.0 (the "License");
+** you may not use this file except in compliance with the License.
+** You may obtain a copy of the License at
+**
+** http://www.apache.org/licenses/LICENSE-2.0
+**
+** Unless required by applicable law or agreed to in writing, software
+** distributed under the License is distributed on an "AS IS" BASIS,
+** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+** See the License for the specific language governing permissions and
+** limitations under the License.
+*/
+package android.app.trust;
+
+/**
+ * Private API to be notified about strong auth changes
+ *
+ * {@hide}
+ */
+oneway interface IStrongAuthTracker {
+ void onStrongAuthRequiredChanged(int strongAuthRequired, int userId);
+} \ No newline at end of file
diff --git a/core/java/android/app/trust/ITrustManager.aidl b/core/java/android/app/trust/ITrustManager.aidl
index 32951d9..2dea545 100644
--- a/core/java/android/app/trust/ITrustManager.aidl
+++ b/core/java/android/app/trust/ITrustManager.aidl
@@ -26,11 +26,9 @@ import android.app.trust.ITrustListener;
interface ITrustManager {
void reportUnlockAttempt(boolean successful, int userId);
void reportEnabledTrustAgentsChanged(int userId);
- void reportRequireCredentialEntry(int userId);
void registerTrustListener(in ITrustListener trustListener);
void unregisterTrustListener(in ITrustListener trustListener);
void reportKeyguardShowingChanged();
boolean isDeviceLocked(int userId);
boolean isDeviceSecure(int userId);
- boolean hasUserAuthenticatedSinceBoot(int userId);
}
diff --git a/core/java/android/app/trust/TrustManager.java b/core/java/android/app/trust/TrustManager.java
index 8cab565..aff69f0 100644
--- a/core/java/android/app/trust/TrustManager.java
+++ b/core/java/android/app/trust/TrustManager.java
@@ -16,13 +16,19 @@
package android.app.trust;
+import android.annotation.IntDef;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.RemoteException;
+import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
+import android.util.SparseIntArray;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* See {@link com.android.server.trust.TrustManagerService}
@@ -73,21 +79,6 @@ public class TrustManager {
}
/**
- * Reports that trust is disabled until credentials have been entered for user {@param userId}.
- *
- * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
- *
- * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
- */
- public void reportRequireCredentialEntry(int userId) {
- try {
- mService.reportRequireCredentialEntry(userId);
- } catch (RemoteException e) {
- onError(e);
- }
- }
-
- /**
* Reports that the visibility of the keyguard has changed.
*
* Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
@@ -147,23 +138,6 @@ public class TrustManager {
}
}
- /**
- * Checks whether the specified user has been authenticated since the last boot.
- *
- * @param userId the user id of the user to check for
- * @return true if the user has authenticated since boot, false otherwise
- *
- * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
- */
- public boolean hasUserAuthenticatedSinceBoot(int userId) {
- try {
- return mService.hasUserAuthenticatedSinceBoot(userId);
- } catch (RemoteException e) {
- onError(e);
- return false;
- }
- }
-
private void onError(Exception e) {
Log.e(TAG, "Error while calling TrustManagerService", e);
}
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index dfb7c50..4e4552d 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -16,6 +16,7 @@
package com.android.internal.widget;
+import android.app.trust.IStrongAuthTracker;
import com.android.internal.widget.VerifyCredentialResponse;
/** {@hide} */
@@ -35,4 +36,7 @@ interface ILockSettings {
boolean checkVoldPassword(int userId);
boolean havePattern(int userId);
boolean havePassword(int userId);
+ void registerStrongAuthTracker(in IStrongAuthTracker tracker);
+ void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
+ void requireStrongAuth(int strongAuthReason, int userId);
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 86d11be..b3871f1 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -16,18 +16,19 @@
package com.android.internal.widget;
-import android.Manifest;
+import android.annotation.IntDef;
import android.app.ActivityManager;
-import android.app.ActivityManagerNative;
import android.app.admin.DevicePolicyManager;
+import android.app.trust.IStrongAuthTracker;
import android.app.trust.TrustManager;
-import android.bluetooth.BluetoothClass;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.os.AsyncTask;
+import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.SystemClock;
@@ -38,9 +39,12 @@ import android.os.storage.StorageManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
+import android.util.SparseIntArray;
import com.google.android.collect.Lists;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
@@ -228,7 +232,7 @@ public class LockPatternUtils {
public void reportFailedPasswordAttempt(int userId) {
getDevicePolicyManager().reportFailedPasswordAttempt(userId);
getTrustManager().reportUnlockAttempt(false /* authenticated */, userId);
- getTrustManager().reportRequireCredentialEntry(userId);
+ requireCredentialEntry(userId);
}
public void reportSuccessfulPasswordAttempt(int userId) {
@@ -1163,10 +1167,32 @@ public class LockPatternUtils {
}
/**
- * @see android.app.trust.TrustManager#reportRequireCredentialEntry(int)
+ * Disable trust until credentials have been entered for user {@param userId}.
+ *
+ * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+ *
+ * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
*/
public void requireCredentialEntry(int userId) {
- getTrustManager().reportRequireCredentialEntry(userId);
+ requireStrongAuth(StrongAuthTracker.SOME_AUTH_REQUIRED_AFTER_USER_REQUEST, userId);
+ }
+
+ /**
+ * Requests strong authentication for user {@param userId}.
+ *
+ * Requires the {@link android.Manifest.permission#ACCESS_KEYGUARD_SECURE_STORAGE} permission.
+ *
+ * @param strongAuthReason a combination of {@link StrongAuthTracker.StrongAuthFlags} indicating
+ * the reason for and the strength of the requested authentication.
+ * @param userId either an explicit user id or {@link android.os.UserHandle#USER_ALL}
+ */
+ public void requireStrongAuth(@StrongAuthTracker.StrongAuthFlags int strongAuthReason,
+ int userId) {
+ try {
+ getLockSettings().requireStrongAuth(strongAuthReason, userId);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error while requesting strong auth: " + e);
+ }
}
private void onAfterChangingPassword(int userHandle) {
@@ -1198,4 +1224,148 @@ public class LockPatternUtils {
private boolean shouldEncryptWithCredentials(boolean defaultValue) {
return isCredentialRequiredToDecrypt(defaultValue) && !isDoNotAskCredentialsOnBootSet();
}
+
+
+ public void registerStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
+ try {
+ getLockSettings().registerStrongAuthTracker(strongAuthTracker.mStub);
+ } catch (RemoteException e) {
+ throw new RuntimeException("Could not register StrongAuthTracker");
+ }
+ }
+
+ public void unregisterStrongAuthTracker(final StrongAuthTracker strongAuthTracker) {
+ try {
+ getLockSettings().unregisterStrongAuthTracker(strongAuthTracker.mStub);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Could not unregister StrongAuthTracker", e);
+ }
+ }
+
+ /**
+ * Tracks the global strong authentication state.
+ */
+ public static class StrongAuthTracker {
+
+ @IntDef(flag = true,
+ value = { STRONG_AUTH_NOT_REQUIRED,
+ STRONG_AUTH_REQUIRED_AFTER_BOOT,
+ STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
+ SOME_AUTH_REQUIRED_AFTER_USER_REQUEST})
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface StrongAuthFlags {}
+
+ /**
+ * Strong authentication is not required.
+ */
+ public static final int STRONG_AUTH_NOT_REQUIRED = 0x0;
+
+ /**
+ * Strong authentication is required because the user has not authenticated since boot.
+ */
+ public static final int STRONG_AUTH_REQUIRED_AFTER_BOOT = 0x1;
+
+ /**
+ * Strong authentication is required because a device admin has requested it.
+ */
+ public static final int STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW = 0x2;
+
+ /**
+ * Some authentication is required because the user has temporarily disabled trust.
+ */
+ public static final int SOME_AUTH_REQUIRED_AFTER_USER_REQUEST = 0x4;
+
+ public static final int DEFAULT = STRONG_AUTH_REQUIRED_AFTER_BOOT;
+ private static final int ALLOWING_FINGERPRINT = SOME_AUTH_REQUIRED_AFTER_USER_REQUEST;
+
+ final SparseIntArray mStrongAuthRequiredForUser = new SparseIntArray();
+
+ private final H mHandler;
+
+ public StrongAuthTracker() {
+ this(Looper.myLooper());
+ }
+
+ /**
+ * @param looper the looper on whose thread calls to {@link #onStrongAuthRequiredChanged}
+ * will be scheduled.
+ */
+ public StrongAuthTracker(Looper looper) {
+ mHandler = new H(looper);
+ }
+
+ /**
+ * Returns {@link #STRONG_AUTH_NOT_REQUIRED} if strong authentication is not required,
+ * otherwise returns a combination of {@link StrongAuthFlags} indicating why strong
+ * authentication is required.
+ *
+ * @param userId the user for whom the state is queried.
+ */
+ public @StrongAuthFlags int getStrongAuthForUser(int userId) {
+ return mStrongAuthRequiredForUser.get(userId, DEFAULT);
+ }
+
+ /**
+ * @return true if unlocking with trust alone is allowed for {@param userId} by the current
+ * strong authentication requirements.
+ */
+ public boolean isTrustAllowedForUser(int userId) {
+ return getStrongAuthForUser(userId) == STRONG_AUTH_NOT_REQUIRED;
+ }
+
+ /**
+ * @return true if unlocking with fingerprint alone is allowed for {@param userId} by the
+ * current strong authentication requirements.
+ */
+ public boolean isFingerprintAllowedForUser(int userId) {
+ return (getStrongAuthForUser(userId) & ~ALLOWING_FINGERPRINT) == 0;
+ }
+
+ /**
+ * Called when the strong authentication requirements for {@param userId} changed.
+ */
+ public void onStrongAuthRequiredChanged(int userId) {
+ }
+
+ void handleStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
+ int userId) {
+
+ int oldValue = getStrongAuthForUser(userId);
+ if (strongAuthFlags != oldValue) {
+ if (strongAuthFlags == DEFAULT) {
+ mStrongAuthRequiredForUser.delete(userId);
+ } else {
+ mStrongAuthRequiredForUser.put(userId, strongAuthFlags);
+ }
+ onStrongAuthRequiredChanged(userId);
+ }
+ }
+
+
+ final IStrongAuthTracker.Stub mStub = new IStrongAuthTracker.Stub() {
+ @Override
+ public void onStrongAuthRequiredChanged(@StrongAuthFlags int strongAuthFlags,
+ int userId) {
+ mHandler.obtainMessage(H.MSG_ON_STRONG_AUTH_REQUIRED_CHANGED,
+ strongAuthFlags, userId).sendToTarget();
+ }
+ };
+
+ private class H extends Handler {
+ static final int MSG_ON_STRONG_AUTH_REQUIRED_CHANGED = 1;
+
+ public H(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_ON_STRONG_AUTH_REQUIRED_CHANGED:
+ handleStrongAuthRequiredChanged(msg.arg1, msg.arg2);
+ break;
+ }
+ }
+ };
+ }
}
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index afa5ae2..cb39e77 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -58,6 +58,7 @@ import com.android.internal.telephony.IccCardConstants;
import com.android.internal.telephony.IccCardConstants.State;
import com.android.internal.telephony.PhoneConstants;
import com.android.internal.telephony.TelephonyIntents;
+import com.android.internal.widget.LockPatternUtils;
import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -170,7 +171,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
private boolean mFingerprintAlreadyAuthenticated;
private boolean mBouncer;
private boolean mBootCompleted;
- private boolean mUserHasAuthenticatedSinceBoot;
// Device provisioning state
private boolean mDeviceProvisioned;
@@ -183,6 +183,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
/** Tracks whether strong authentication hasn't been used since quite some time per user. */
private ArraySet<Integer> mStrongAuthTimedOut = new ArraySet<>();
+ private final StrongAuthTracker mStrongAuthTracker = new StrongAuthTracker();
private final ArrayList<WeakReference<KeyguardUpdateMonitorCallback>>
mCallbacks = Lists.newArrayList();
@@ -539,7 +540,12 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
public boolean isUnlockingWithFingerprintAllowed() {
- return mUserHasAuthenticatedSinceBoot && !hasFingerprintUnlockTimedOut(sCurrentUser);
+ return mStrongAuthTracker.isUnlockingWithFingerprintAllowed()
+ && !hasFingerprintUnlockTimedOut(sCurrentUser);
+ }
+
+ public StrongAuthTracker getStrongAuthTracker() {
+ return mStrongAuthTracker;
}
/**
@@ -827,6 +833,25 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
}
}
+ public class StrongAuthTracker extends LockPatternUtils.StrongAuthTracker {
+
+ public boolean isUnlockingWithFingerprintAllowed() {
+ int userId = getCurrentUser();
+ return isFingerprintAllowedForUser(userId);
+ }
+
+ public boolean hasUserAuthenticatedSinceBoot() {
+ int userId = getCurrentUser();
+ return (getStrongAuthForUser(userId)
+ & STRONG_AUTH_REQUIRED_AFTER_BOOT) == 0;
+ }
+
+ @Override
+ public void onStrongAuthRequiredChanged(int userId) {
+ // do something?
+ }
+ }
+
public static KeyguardUpdateMonitor getInstance(Context context) {
if (sInstance == null) {
sInstance = new KeyguardUpdateMonitor(context);
@@ -973,6 +998,7 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
PERMISSION_SELF, null /* handler */);
mTrustManager = (TrustManager) context.getSystemService(Context.TRUST_SERVICE);
mTrustManager.registerTrustListener(this);
+ new LockPatternUtils(context).registerStrongAuthTracker(mStrongAuthTracker);
mFpm = (FingerprintManager) context.getSystemService(Context.FINGERPRINT_SERVICE);
updateFingerprintListeningState();
@@ -1001,8 +1027,6 @@ public class KeyguardUpdateMonitor implements TrustManager.TrustListener {
if (DEBUG) Log.v(TAG, "startListeningForFingerprint()");
int userId = ActivityManager.getCurrentUser();
if (isUnlockWithFingerprintPossible(userId)) {
- mUserHasAuthenticatedSinceBoot = mTrustManager.hasUserAuthenticatedSinceBoot(
- ActivityManager.getCurrentUser());
if (mFingerprintCancelSignal != null) {
mFingerprintCancelSignal.cancel();
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index ce91d5b..647b272 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -531,7 +531,7 @@ public class KeyguardViewMediator extends SystemUI {
int currentUser = ActivityManager.getCurrentUser();
if ((mUpdateMonitor.getUserTrustIsManaged(currentUser)
|| mUpdateMonitor.isUnlockWithFingerprintPossible(currentUser))
- && !mTrustManager.hasUserAuthenticatedSinceBoot(currentUser)) {
+ && !mUpdateMonitor.getStrongAuthTracker().hasUserAuthenticatedSinceBoot()) {
return KeyguardSecurityView.PROMPT_REASON_RESTART;
} else if (mUpdateMonitor.isUnlockWithFingerprintPossible(currentUser)
&& mUpdateMonitor.hasFingerprintUnlockTimedOut(currentUser)) {
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 5e2fe5a..005d6a4 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -18,6 +18,7 @@ package com.android.server;
import android.app.admin.DevicePolicyManager;
import android.app.backup.BackupManager;
+import android.app.trust.IStrongAuthTracker;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -70,6 +71,7 @@ public class LockSettingsService extends ILockSettings.Stub {
private final Context mContext;
private final LockSettingsStorage mStorage;
+ private final LockSettingsStrongAuth mStrongAuth = new LockSettingsStrongAuth();
private LockPatternUtils mLockPatternUtils;
private boolean mFirstCallToVold;
@@ -93,6 +95,7 @@ public class LockSettingsService extends ILockSettings.Stub {
filter.addAction(Intent.ACTION_USER_ADDED);
filter.addAction(Intent.ACTION_USER_STARTING);
filter.addAction(Intent.ACTION_USER_REMOVED);
+ filter.addAction(Intent.ACTION_USER_PRESENT);
mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
@@ -122,6 +125,8 @@ public class LockSettingsService extends ILockSettings.Stub {
} else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
mStorage.prefetchUser(userHandle);
+ } else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
+ mStrongAuth.reportUnlock(getSendingUserId());
} else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
if (userHandle > 0) {
@@ -713,6 +718,7 @@ public class LockSettingsService extends ILockSettings.Stub {
private void removeUser(int userId) {
mStorage.removeUser(userId);
+ mStrongAuth.removeUser(userId);
final KeyStore ks = KeyStore.getInstance();
ks.onUserRemoved(userId);
@@ -727,6 +733,24 @@ public class LockSettingsService extends ILockSettings.Stub {
}
}
+ @Override
+ public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
+ checkPasswordReadPermission(UserHandle.USER_ALL);
+ mStrongAuth.registerStrongAuthTracker(tracker);
+ }
+
+ @Override
+ public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
+ checkPasswordReadPermission(UserHandle.USER_ALL);
+ mStrongAuth.unregisterStrongAuthTracker(tracker);
+ }
+
+ @Override
+ public void requireStrongAuth(int strongAuthReason, int userId) {
+ checkWritePermission(userId);
+ mStrongAuth.requireStrongAuth(strongAuthReason, userId);
+ }
+
private static final String[] VALID_SETTINGS = new String[] {
LockPatternUtils.LOCKOUT_PERMANENT_KEY,
LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
@@ -797,5 +821,4 @@ public class LockSettingsService extends ILockSettings.Stub {
Slog.e(TAG, "Unable to acquire GateKeeperService");
return null;
}
-
}
diff --git a/services/core/java/com/android/server/LockSettingsStrongAuth.java b/services/core/java/com/android/server/LockSettingsStrongAuth.java
new file mode 100644
index 0000000..c023f4a
--- /dev/null
+++ b/services/core/java/com/android/server/LockSettingsStrongAuth.java
@@ -0,0 +1,167 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.server;
+
+import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
+
+import android.app.trust.IStrongAuthTracker;
+import android.os.DeadObjectException;
+import android.os.Handler;
+import android.os.Message;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Slog;
+import android.util.SparseIntArray;
+
+import java.util.ArrayList;
+
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_NOT_REQUIRED;
+
+/**
+ * Keeps track of requests for strong authentication.
+ */
+public class LockSettingsStrongAuth {
+
+ private static final String TAG = "LockSettings";
+
+ private static final int MSG_REQUIRE_STRONG_AUTH = 1;
+ private static final int MSG_REGISTER_TRACKER = 2;
+ private static final int MSG_UNREGISTER_TRACKER = 3;
+ private static final int MSG_REMOVE_USER = 4;
+
+ private final ArrayList<IStrongAuthTracker> mStrongAuthTrackers = new ArrayList<>();
+ private final SparseIntArray mStrongAuthForUser = new SparseIntArray();
+
+ private void handleAddStrongAuthTracker(IStrongAuthTracker tracker) {
+ for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
+ if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) {
+ return;
+ }
+ }
+ mStrongAuthTrackers.add(tracker);
+
+ for (int i = 0; i < mStrongAuthForUser.size(); i++) {
+ int key = mStrongAuthForUser.keyAt(i);
+ int value = mStrongAuthForUser.valueAt(i);
+ try {
+ tracker.onStrongAuthRequiredChanged(value, key);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception while adding StrongAuthTracker.", e);
+ }
+ }
+ }
+
+ private void handleRemoveStrongAuthTracker(IStrongAuthTracker tracker) {
+ for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
+ if (mStrongAuthTrackers.get(i).asBinder() == tracker.asBinder()) {
+ mStrongAuthTrackers.remove(i);
+ return;
+ }
+ }
+ }
+
+ private void handleRequireStrongAuth(int strongAuthReason, int userId) {
+ if (userId == UserHandle.USER_ALL) {
+ for (int i = 0; i < mStrongAuthForUser.size(); i++) {
+ int key = mStrongAuthForUser.keyAt(i);
+ handleRequireStrongAuthOneUser(strongAuthReason, key);
+ }
+ } else {
+ handleRequireStrongAuthOneUser(strongAuthReason, userId);
+ }
+ }
+
+ private void handleRequireStrongAuthOneUser(int strongAuthReason, int userId) {
+ int oldValue = mStrongAuthForUser.get(userId, LockPatternUtils.StrongAuthTracker.DEFAULT);
+ int newValue = strongAuthReason == STRONG_AUTH_NOT_REQUIRED
+ ? STRONG_AUTH_NOT_REQUIRED
+ : (oldValue | strongAuthReason);
+ if (oldValue != newValue) {
+ mStrongAuthForUser.put(userId, newValue);
+ notifyStrongAuthTrackers(newValue, userId);
+ }
+ }
+
+ private void handleRemoveUser(int userId) {
+ int index = mStrongAuthForUser.indexOfKey(userId);
+ if (index >= 0) {
+ mStrongAuthForUser.removeAt(index);
+ notifyStrongAuthTrackers(StrongAuthTracker.DEFAULT, userId);
+ }
+ }
+
+ private void notifyStrongAuthTrackers(int strongAuthReason, int userId) {
+ for (int i = 0; i < mStrongAuthTrackers.size(); i++) {
+ try {
+ mStrongAuthTrackers.get(i).onStrongAuthRequiredChanged(strongAuthReason, userId);
+ } catch (DeadObjectException e) {
+ Slog.d(TAG, "Removing dead StrongAuthTracker.");
+ mStrongAuthTrackers.remove(i);
+ i--;
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Exception while notifying StrongAuthTracker.", e);
+ }
+ }
+ }
+
+ public void registerStrongAuthTracker(IStrongAuthTracker tracker) {
+ mHandler.obtainMessage(MSG_REGISTER_TRACKER, tracker).sendToTarget();
+ }
+
+ public void unregisterStrongAuthTracker(IStrongAuthTracker tracker) {
+ mHandler.obtainMessage(MSG_UNREGISTER_TRACKER, tracker).sendToTarget();
+ }
+
+ public void removeUser(int userId) {
+ mHandler.obtainMessage(MSG_REMOVE_USER, userId, 0).sendToTarget();
+ }
+
+ public void requireStrongAuth(int strongAuthReason, int userId) {
+ if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_OWNER) {
+ mHandler.obtainMessage(MSG_REQUIRE_STRONG_AUTH, strongAuthReason,
+ userId).sendToTarget();
+ } else {
+ throw new IllegalArgumentException(
+ "userId must be an explicit user id or USER_ALL");
+ }
+ }
+
+ public void reportUnlock(int userId) {
+ requireStrongAuth(STRONG_AUTH_NOT_REQUIRED, userId);
+ }
+
+ private final Handler mHandler = new Handler() {
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case MSG_REGISTER_TRACKER:
+ handleAddStrongAuthTracker((IStrongAuthTracker) msg.obj);
+ break;
+ case MSG_UNREGISTER_TRACKER:
+ handleRemoveStrongAuthTracker((IStrongAuthTracker) msg.obj);
+ break;
+ case MSG_REQUIRE_STRONG_AUTH:
+ handleRequireStrongAuth(msg.arg1, msg.arg2);
+ break;
+ case MSG_REMOVE_USER:
+ handleRemoveUser(msg.arg1);
+ break;
+ }
+ }
+ };
+}
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 15da829..6c70fe9 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -19,6 +19,7 @@ package com.android.server.trust;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.content.PackageMonitor;
import com.android.internal.widget.LockPatternUtils;
+import com.android.internal.widget.LockPatternUtils.StrongAuthTracker;
import com.android.server.SystemService;
import org.xmlpull.v1.XmlPullParser;
@@ -59,6 +60,7 @@ import android.util.AttributeSet;
import android.util.Log;
import android.util.Slog;
import android.util.SparseBooleanArray;
+import android.util.SparseIntArray;
import android.util.Xml;
import android.view.IWindowManager;
import android.view.WindowManagerGlobal;
@@ -96,16 +98,15 @@ public class TrustManagerService extends SystemService {
private static final int MSG_UNREGISTER_LISTENER = 2;
private static final int MSG_DISPATCH_UNLOCK_ATTEMPT = 3;
private static final int MSG_ENABLED_AGENTS_CHANGED = 4;
- private static final int MSG_REQUIRE_CREDENTIAL_ENTRY = 5;
private static final int MSG_KEYGUARD_SHOWING_CHANGED = 6;
private static final int MSG_START_USER = 7;
private static final int MSG_CLEANUP_USER = 8;
private static final int MSG_SWITCH_USER = 9;
- private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<AgentInfo>();
- private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<ITrustListener>();
+ private final ArraySet<AgentInfo> mActiveAgents = new ArraySet<>();
+ private final ArrayList<ITrustListener> mTrustListeners = new ArrayList<>();
private final Receiver mReceiver = new Receiver();
- private final SparseBooleanArray mUserHasAuthenticated = new SparseBooleanArray();
+
/* package */ final TrustArchive mArchive = new TrustArchive();
private final Context mContext;
private final LockPatternUtils mLockPatternUtils;
@@ -118,9 +119,6 @@ public class TrustManagerService extends SystemService {
@GuardedBy("mDeviceLockedForUser")
private final SparseBooleanArray mDeviceLockedForUser = new SparseBooleanArray();
- @GuardedBy("mUserHasAuthenticatedSinceBoot")
- private final SparseBooleanArray mUserHasAuthenticatedSinceBoot = new SparseBooleanArray();
-
private boolean mTrustAgentsCanRun = false;
private int mCurrentUser = UserHandle.USER_OWNER;
@@ -146,6 +144,7 @@ public class TrustManagerService extends SystemService {
if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
mReceiver.register(mContext);
+ mLockPatternUtils.registerStrongAuthTracker(mStrongAuthTracker);
} else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
mTrustAgentsCanRun = true;
refreshAgentList(UserHandle.USER_ALL);
@@ -230,7 +229,7 @@ public class TrustManagerService extends SystemService {
if (!userInfo.supportsSwitchTo()) continue;
if (!mActivityManager.isUserRunning(userInfo.id)) continue;
if (!lockPatternUtils.isSecure(userInfo.id)) continue;
- if (!getUserHasAuthenticated(userInfo.id)) continue;
+ if (!mStrongAuthTracker.isTrustAllowedForUser(userInfo.id)) continue;
DevicePolicyManager dpm = lockPatternUtils.getDevicePolicyManager();
int disabledFeatures = dpm.getKeyguardDisabledFeatures(null, userInfo.id);
final boolean disableTrustAgents =
@@ -509,7 +508,7 @@ public class TrustManagerService extends SystemService {
// Agent dispatch and aggregation
private boolean aggregateIsTrusted(int userId) {
- if (!getUserHasAuthenticated(userId)) {
+ if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) {
return false;
}
for (int i = 0; i < mActiveAgents.size(); i++) {
@@ -524,7 +523,7 @@ public class TrustManagerService extends SystemService {
}
private boolean aggregateIsTrustManaged(int userId) {
- if (!getUserHasAuthenticated(userId)) {
+ if (!mStrongAuthTracker.isTrustAllowedForUser(userId)) {
return false;
}
for (int i = 0; i < mActiveAgents.size(); i++) {
@@ -545,54 +544,6 @@ public class TrustManagerService extends SystemService {
info.agent.onUnlockAttempt(successful);
}
}
-
- if (successful) {
- updateUserHasAuthenticated(userId);
- }
- }
-
- private void updateUserHasAuthenticated(int userId) {
- boolean changed = setUserHasAuthenticated(userId);
- if (changed) {
- refreshAgentList(userId);
- }
- }
-
- private boolean getUserHasAuthenticated(int userId) {
- return mUserHasAuthenticated.get(userId);
- }
-
- /**
- * @return whether the value has changed
- */
- private boolean setUserHasAuthenticated(int userId) {
- if (!mUserHasAuthenticated.get(userId)) {
- mUserHasAuthenticated.put(userId, true);
- synchronized (mUserHasAuthenticatedSinceBoot) {
- mUserHasAuthenticatedSinceBoot.put(userId, true);
- }
- return true;
- }
- return false;
- }
-
- private void clearUserHasAuthenticated(int userId) {
- if (userId == UserHandle.USER_ALL) {
- mUserHasAuthenticated.clear();
- } else {
- mUserHasAuthenticated.put(userId, false);
- }
- }
-
- private boolean getUserHasAuthenticatedSinceBoot(int userId) {
- synchronized (mUserHasAuthenticatedSinceBoot) {
- return mUserHasAuthenticatedSinceBoot.get(userId);
- }
- }
-
- private void requireCredentialEntry(int userId) {
- clearUserHasAuthenticated(userId);
- refreshAgentList(userId);
}
// Listeners
@@ -681,17 +632,6 @@ public class TrustManagerService extends SystemService {
}
@Override
- public void reportRequireCredentialEntry(int userId) throws RemoteException {
- enforceReportPermission();
- if (userId == UserHandle.USER_ALL || userId >= UserHandle.USER_OWNER) {
- mHandler.obtainMessage(MSG_REQUIRE_CREDENTIAL_ENTRY, userId, 0).sendToTarget();
- } else {
- throw new IllegalArgumentException(
- "userId must be an explicit user id or USER_ALL");
- }
- }
-
- @Override
public void reportKeyguardShowingChanged() throws RemoteException {
enforceReportPermission();
// coalesce refresh messages.
@@ -734,18 +674,6 @@ public class TrustManagerService extends SystemService {
}
}
- @Override
- public boolean hasUserAuthenticatedSinceBoot(int userId) throws RemoteException {
- mContext.enforceCallingOrSelfPermission(
- Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, null);
- long token = Binder.clearCallingIdentity();
- try {
- return getUserHasAuthenticatedSinceBoot(userId);
- } finally {
- Binder.restoreCallingIdentity(token);
- }
- }
-
private void enforceReportPermission() {
mContext.enforceCallingOrSelfPermission(
Manifest.permission.ACCESS_KEYGUARD_SECURE_STORAGE, "reporting trust events");
@@ -794,9 +722,8 @@ public class TrustManagerService extends SystemService {
fout.print(": trusted=" + dumpBool(aggregateIsTrusted(user.id)));
fout.print(", trustManaged=" + dumpBool(aggregateIsTrustManaged(user.id)));
fout.print(", deviceLocked=" + dumpBool(isDeviceLockedInner(user.id)));
- fout.print(", hasAuthenticated=" + dumpBool(getUserHasAuthenticated(user.id)));
- fout.print(", hasAuthenticatedSinceBoot="
- + dumpBool(getUserHasAuthenticatedSinceBoot(user.id)));
+ fout.print(", strongAuthRequired=" + dumpHex(
+ mStrongAuthTracker.getStrongAuthForUser(user.id)));
fout.println();
fout.println(" Enabled agents:");
boolean duplicateSimpleNames = false;
@@ -831,6 +758,10 @@ public class TrustManagerService extends SystemService {
private String dumpBool(boolean b) {
return b ? "1" : "0";
}
+
+ private String dumpHex(int i) {
+ return "0x" + Integer.toHexString(i);
+ }
};
private int resolveProfileParent(int userId) {
@@ -864,9 +795,6 @@ public class TrustManagerService extends SystemService {
// This is also called when the security mode of a user changes.
refreshDeviceLockedForUser(UserHandle.USER_ALL);
break;
- case MSG_REQUIRE_CREDENTIAL_ENTRY:
- requireCredentialEntry(msg.arg1);
- break;
case MSG_KEYGUARD_SHOWING_CHANGED:
refreshDeviceLockedForUser(mCurrentUser);
break;
@@ -900,6 +828,13 @@ public class TrustManagerService extends SystemService {
}
};
+ private final StrongAuthTracker mStrongAuthTracker = new StrongAuthTracker() {
+ @Override
+ public void onStrongAuthRequiredChanged(int userId) {
+ refreshAgentList(userId);
+ }
+ };
+
private class Receiver extends BroadcastReceiver {
@Override
@@ -908,8 +843,6 @@ public class TrustManagerService extends SystemService {
if (DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED.equals(action)) {
refreshAgentList(getSendingUserId());
updateDevicePolicyFeatures();
- } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
- updateUserHasAuthenticated(getSendingUserId());
} else if (Intent.ACTION_USER_ADDED.equals(action)) {
int userId = getUserId(intent);
if (userId > 0) {
@@ -918,7 +851,6 @@ public class TrustManagerService extends SystemService {
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
int userId = getUserId(intent);
if (userId > 0) {
- mUserHasAuthenticated.delete(userId);
synchronized (mUserIsTrusted) {
mUserIsTrusted.delete(userId);
}
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index cd2885b..dedf1d9 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -21,6 +21,7 @@ import static android.app.admin.DevicePolicyManager.PASSWORD_QUALITY_COMPLEX;
import static android.app.admin.DevicePolicyManager.WIPE_EXTERNAL_STORAGE;
import static android.app.admin.DevicePolicyManager.WIPE_RESET_PROTECTION_DATA;
import static android.content.pm.PackageManager.GET_UNINSTALLED_PACKAGES;
+import static com.android.internal.widget.LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW;
import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
import static org.xmlpull.v1.XmlPullParser.END_TAG;
import static org.xmlpull.v1.XmlPullParser.TEXT;
@@ -44,6 +45,7 @@ import android.app.admin.DevicePolicyManagerInternal;
import android.app.admin.IDevicePolicyManager;
import android.app.admin.SystemUpdatePolicy;
import android.app.backup.IBackupManager;
+import android.app.trust.TrustManager;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.ContentResolver;
@@ -2957,7 +2959,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
}
boolean requireEntry = (flags & DevicePolicyManager.RESET_PASSWORD_REQUIRE_ENTRY) != 0;
if (requireEntry) {
- utils.requireCredentialEntry(UserHandle.USER_ALL);
+ utils.requireStrongAuth(STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW,
+ UserHandle.USER_ALL);
}
synchronized (this) {
int newOwner = requireEntry ? callingUid : -1;
@@ -3089,7 +3092,8 @@ public class DevicePolicyManagerService extends IDevicePolicyManager.Stub {
mPowerManager.goToSleep(SystemClock.uptimeMillis(),
PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0);
// Ensure the device is locked
- new LockPatternUtils(mContext).requireCredentialEntry(UserHandle.USER_ALL);
+ new LockPatternUtils(mContext).requireStrongAuth(
+ STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, UserHandle.USER_ALL);
getWindowManager().lockNow(null);
} catch (RemoteException e) {
} finally {