Merge "Fingerprint: get auth id for non-current user." into nyc-mr2-dev
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index f17fd55..c5ae1f5 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -710,7 +710,7 @@
 
     /**
      * Retrieves the authenticator token for binding keys to the lifecycle
-     * of the current set of fingerprints. Used only by internal clients.
+     * of the calling user's fingerprints. Used only by internal clients.
      *
      * @hide
      */
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 6c11794..e640823 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -74,6 +74,7 @@
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 /**
  * A service to manage multiple clients that want to access the fingerprint HAL API.
@@ -101,6 +102,8 @@
 
     private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
             new ArrayList<>();
+    private final Map<Integer, Long> mAuthenticatorIds =
+            Collections.synchronizedMap(new HashMap<>());
     private final AppOpsManager mAppOps;
     private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
     private static final int MAX_FAILED_ATTEMPTS = 5;
@@ -117,7 +120,6 @@
     private final UserManager mUserManager;
     private ClientMonitor mCurrentClient;
     private ClientMonitor mPendingClient;
-    private long mCurrentAuthenticatorId;
     private PerformanceStats mPerformanceStats;
 
     // Normal fingerprint authentications are tracked by mPerformanceMap.
@@ -209,6 +211,7 @@
                     mDaemon.init(mDaemonCallback);
                     mHalDeviceId = mDaemon.openHal();
                     if (mHalDeviceId != 0) {
+                        loadAuthenticatorIds();
                         updateActiveGroup(ActivityManager.getCurrentUser(), null);
                     } else {
                         Slog.w(TAG, "Failed to open Fingerprint HAL!");
@@ -226,6 +229,26 @@
         return mDaemon;
     }
 
+    /** Populates existing authenticator ids. To be used only during the start of the service. */
+    private void loadAuthenticatorIds() {
+        // This operation can be expensive, so keep track of the elapsed time. Might need to move to
+        // background if it takes too long.
+        long t = System.currentTimeMillis();
+
+        mAuthenticatorIds.clear();
+        for (UserInfo user : UserManager.get(mContext).getUsers(true /* excludeDying */)) {
+            int userId = getUserOrWorkProfileId(null, user.id);
+            if (!mAuthenticatorIds.containsKey(userId)) {
+                updateActiveGroup(userId, null);
+            }
+        }
+
+        t = System.currentTimeMillis() - t;
+        if (t > 1000) {
+            Slog.w(TAG, "loadAuthenticatorIds() taking too long: " + t + "ms");
+        }
+    }
+
     protected void handleEnumerate(long deviceId, int[] fingerIds, int[] groupIds) {
         if (fingerIds.length != groupIds.length) {
             Slog.w(TAG, "fingerIds and groupIds differ in length: f[]="
@@ -443,14 +466,23 @@
 
     boolean isCurrentUserOrProfile(int userId) {
         UserManager um = UserManager.get(mContext);
-
-        // Allow current user or profiles of the current user...
-        for (int profileId : um.getEnabledProfileIds(userId)) {
-            if (profileId == userId) {
-                return true;
-            }
+        if (um == null) {
+            Slog.e(TAG, "Unable to acquire UserManager");
+            return false;
         }
-        return false;
+
+        final long token = Binder.clearCallingIdentity();
+        try {
+            // Allow current user or profiles of the current user...
+            for (int profileId : um.getEnabledProfileIds(mCurrentUserId)) {
+                if (profileId == userId) {
+                    return true;
+                }
+            }
+            return false;
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
     }
 
     private boolean isForegroundActivity(int uid, int pid) {
@@ -1035,7 +1067,7 @@
                     daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes());
                     mCurrentUserId = userId;
                 }
-                mCurrentAuthenticatorId = daemon.getAuthenticatorId();
+                mAuthenticatorIds.put(userId, daemon.getAuthenticatorId());
             } catch (RemoteException e) {
                 Slog.e(TAG, "Failed to setActiveGroup():", e);
             }
@@ -1058,8 +1090,14 @@
      * @return true if this is a work profile
      */
     private boolean isWorkProfile(int userId) {
-        UserInfo info = mUserManager.getUserInfo(userId);
-        return info != null && info.isManagedProfile();
+        UserInfo userInfo = null;
+        final long token = Binder.clearCallingIdentity();
+        try {
+            userInfo = mUserManager.getUserInfo(userId);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+        return userInfo != null && userInfo.isManagedProfile();
     }
 
     private void listenForUserSwitches() {
@@ -1085,12 +1123,14 @@
         }
     }
 
-    /***
+    /**
      * @param opPackageName the name of the calling package
-     * @return authenticator id for the current user
+     * @return authenticator id for the calling user
      */
     public long getAuthenticatorId(String opPackageName) {
-        return mCurrentAuthenticatorId;
+        final int userId = getUserOrWorkProfileId(opPackageName, UserHandle.getCallingUserId());
+        Long authenticatorId = mAuthenticatorIds.get(userId);
+        return authenticatorId != null ? authenticatorId : 0;
     }
 
 }