Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d1f722d9 authored by Clara Bayarri's avatar Clara Bayarri
Browse files

Enable enrolling/authenticating a specific work profile.

This change adds support for a separate profile-specific
fingerprint database. This is to be used together with the work
challenge.

Change-Id: I65b3a74a1c887def210d7a6da0b907138f58a5ba
parent 6cfdf6b6
Loading
Loading
Loading
Loading
+20 −2
Original line number Diff line number Diff line
@@ -496,7 +496,10 @@ public class FingerprintManager {
     */
    @RequiresPermission(MANAGE_FINGERPRINT)
    public void enroll(byte [] token, CancellationSignal cancel, int flags,
            EnrollmentCallback callback) {
            EnrollmentCallback callback, int userId) {
        if (userId == UserHandle.USER_CURRENT) {
            userId = getCurrentUserId();
        }
        if (callback == null) {
            throw new IllegalArgumentException("Must supply an enrollment callback");
        }
@@ -512,7 +515,7 @@ public class FingerprintManager {

        if (mService != null) try {
            mEnrollmentCallback = callback;
            mService.enroll(mToken, token, getCurrentUserId(), mServiceReceiver, flags);
            mService.enroll(mToken, token, userId, mServiceReceiver, flags);
        } catch (RemoteException e) {
            Log.w(TAG, "Remote exception in enroll: ", e);
            if (callback != null) {
@@ -555,6 +558,21 @@ public class FingerprintManager {
        return result;
    }

    /**
     * Sets the active user. This is meant to be used to select the current profile for enrollment
     * to allow separate enrolled fingers for a work profile
     * @param userId
     * @hide
     */
    @RequiresPermission(MANAGE_FINGERPRINT)
    public void setActiveUser(int userId) {
        if (mService != null) try {
            mService.setActiveUser(userId);
        } catch (RemoteException e) {
            Log.w(TAG, "Remote exception in setActiveUser: ", e);
        }
    }

    /**
     * Remove given fingerprint template from fingerprint hardware and/or protected storage.
     * @param fp the fingerprint item to remove
+3 −0
Original line number Diff line number Diff line
@@ -75,4 +75,7 @@ interface IFingerprintService {

    // Add a callback which gets notified when the fingerprint lockout period expired.
    void addLockoutResetCallback(IFingerprintServiceLockoutResetCallback callback);

    // Explicitly set the active user (for enrolling work profile)
    void setActiveUser(int uid);
}
+70 −22
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.fingerprint;
import android.Manifest;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningAppProcessInfo;
import android.app.trust.TrustManager;
import android.app.ActivityManagerNative;
import android.app.AlarmManager;
import android.app.AppOpsManager;
@@ -103,6 +104,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
    private static final int MAX_FAILED_ATTEMPTS = 5;
    private static final int FINGERPRINT_ACQUIRED_GOOD = 0;
    private final String mKeyguardPackage;
    private int mCurrentUserId = UserHandle.USER_CURRENT;

    Handler mHandler = new Handler() {
        @Override
@@ -125,6 +127,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
    private IFingerprintDaemon mDaemon;
    private final PowerManager mPowerManager;
    private final AlarmManager mAlarmManager;
    private final UserManager mUserManager;

    private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() {
        @Override
@@ -152,6 +155,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
        mAlarmManager = mContext.getSystemService(AlarmManager.class);
        mContext.registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET),
                RESET_FINGERPRINT_LOCKOUT, null /* handler */);
        mUserManager = UserManager.get(mContext);
    }

    @Override
@@ -170,7 +174,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
                    mDaemon.init(mDaemonCallback);
                    mHalDeviceId = mDaemon.openHal();
                    if (mHalDeviceId != 0) {
                        updateActiveGroup(ActivityManager.getCurrentUser());
                        updateActiveGroup(ActivityManager.getCurrentUser(), null);
                    } else {
                        Slog.w(TAG, "Failed to open Fingerprint HAL!");
                        mDaemon = null;
@@ -261,7 +265,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
    }

    void handleUserSwitching(int userId) {
        updateActiveGroup(userId);
        updateActiveGroup(userId, null);
    }

    private void removeClient(ClientMonitor client) {
@@ -414,7 +418,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
        removeClient(mEnrollClient);
    }

    void startAuthentication(IBinder token, long opId, int groupId,
    void startAuthentication(IBinder token, long opId, int realUserId, int groupId,
            IFingerprintServiceReceiver receiver, int flags, boolean restricted,
            String opPackageName) {
        IFingerprintDaemon daemon = getFingerprintDaemon();
@@ -423,6 +427,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
            return;
        }
        stopPendingOperations(true);
        updateActiveGroup(groupId, opPackageName);
        mAuthClient = new ClientMonitor(token, receiver, groupId, restricted, opPackageName);
        if (inLockoutMode()) {
            Slog.v(TAG, "In lockout mode; disallowing authentication");
@@ -564,7 +569,7 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
        checkPermission(USE_FINGERPRINT);
        final int uid = Binder.getCallingUid();
        final int pid = Binder.getCallingPid();
        if (opPackageName.equals(mKeyguardPackage)) {
        if (isKeyguard(opPackageName)) {
            return true; // Keyguard is always allowed
        }
        if (!isCurrentUserOrProfile(UserHandle.getCallingUserId())) {
@@ -583,6 +588,14 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
        return true;
    }

    /**
     * @param clientPackage
     * @return true if this is keyguard package
     */
    private boolean isKeyguard(String clientPackage) {
        return mKeyguardPackage.equals(clientPackage);
    }

    private void addLockoutResetMonitor(FingerprintServiceLockoutResetMonitor monitor) {
        if (!mLockoutMonitors.contains(monitor)) {
            mLockoutMonitors.add(monitor);
@@ -927,14 +940,15 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
            // Group ID is arbitrarily set to parent profile user ID. It just represents
            // the default fingerprints for the user.
            final int effectiveGroupId = getEffectiveUserId(groupId);
            final int realUserId = Binder.getCallingUid();

            final boolean restricted = isRestricted();
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    MetricsLogger.histogram(mContext, "fingerprint_token", opId != 0L ? 1 : 0);
                    startAuthentication(token, opId, effectiveGroupId, receiver, flags, restricted,
                            opPackageName);
                    startAuthentication(token, opId, realUserId, effectiveGroupId, receiver,
                            flags, restricted, opPackageName);
                }
            });
        }
@@ -952,6 +966,17 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
            });
        }

        @Override // Binder call
        public void setActiveUser(final int userId) {
            checkPermission(MANAGE_FINGERPRINT);
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    updateActiveGroup(userId, null);
                }
            });
        }

        @Override // Binder call
        public void remove(final IBinder token, final int fingerId, final int groupId,
                final IFingerprintServiceReceiver receiver) {
@@ -1102,11 +1127,12 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
        listenForUserSwitches();
    }

    private void updateActiveGroup(int userId) {
    private void updateActiveGroup(int userId, String clientPackage) {
        IFingerprintDaemon daemon = getFingerprintDaemon();
        if (daemon != null) {
            try {
                userId = getEffectiveUserId(userId);
                userId = getUserOrWorkProfileId(clientPackage, userId);
                if (userId != mCurrentUserId) {
                    final File systemDir = Environment.getUserSystemDirectory(userId);
                    final File fpDir = new File(systemDir, FP_DATA_DIR);
                    if (!fpDir.exists()) {
@@ -1123,12 +1149,34 @@ public class FingerprintService extends SystemService implements IBinder.DeathRe
                        }
                    }
                    daemon.setActiveGroup(userId, fpDir.getAbsolutePath().getBytes());
                    mCurrentUserId = userId;
                }
            } catch (RemoteException e) {
                Slog.e(TAG, "Failed to setActiveGroup():", e);
            }
        }
    }

    /**
     * @param clientPackage the package of the caller
     * @return the profile id
     */
    private int getUserOrWorkProfileId(String clientPackage, int userId) {
        if (!isKeyguard(clientPackage) && isWorkProfile(userId)) {
            return userId;
        }
        return getEffectiveUserId(userId);
    }

    /**
     * @param userId
     * @return true if this is a work profile
     */
    private boolean isWorkProfile(int userId) {
        UserInfo info = mUserManager.getUserInfo(userId);
        return info != null && info.isManagedProfile();
    }

    private void listenForUserSwitches() {
        try {
            ActivityManagerNative.getDefault().registerUserSwitchObserver(