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

Commit 4a5fb772 authored by Curtis Belmonte's avatar Curtis Belmonte
Browse files

Make BiometricServiceBase more robust to HAL crash

Test: atest BiometricServiceBase

Bug: 152135554
Change-Id: I7dcdef581ee9cf970668288da0cf3af5601d1d4c
parent 9928fdd7
Loading
Loading
Loading
Loading
+22 −6
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.server.biometrics;

import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND_SERVICE;
import static android.hardware.biometrics.BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE;

import android.app.ActivityManager;
import android.app.ActivityTaskManager;
@@ -54,6 +55,7 @@ import android.os.UserManager;
import android.util.Slog;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.statusbar.IStatusBarService;
import com.android.internal.util.FrameworkStatsLog;
@@ -672,8 +674,8 @@ public abstract class BiometricServiceBase extends SystemService

        // All client lifecycle must be managed on the handler.
        mHandler.post(() -> {
            handleError(getHalDeviceId(), BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE,
                    0 /*vendorCode */);
            Slog.e(getTag(), "Sending BIOMETRIC_ERROR_HW_UNAVAILABLE after HAL crash");
            handleError(getHalDeviceId(), BIOMETRIC_ERROR_HW_UNAVAILABLE, 0 /* vendorCode */);
        });

        FrameworkStatsLog.write(FrameworkStatsLog.BIOMETRIC_SYSTEM_HEALTH_ISSUE_DETECTED,
@@ -900,12 +902,16 @@ public abstract class BiometricServiceBase extends SystemService

    protected void cancelAuthenticationInternal(final IBinder token, final String opPackageName,
            int callingUid, int callingPid, int callingUserId, boolean fromClient) {

        if (DEBUG) Slog.v(getTag(), "cancelAuthentication(" + opPackageName + ")");
        if (fromClient) {
            // Only check this if cancel was called from the client (app). If cancel was called
            // from BiometricService, it means the dialog was dismissed due to user interaction.
            if (!canUseBiometric(opPackageName, true /* foregroundOnly */, callingUid, callingPid,
                    callingUserId)) {
                if (DEBUG) Slog.v(getTag(), "cancelAuthentication(): reject " + opPackageName);
                if (DEBUG) {
                    Slog.v(getTag(), "cancelAuthentication(): reject " + opPackageName);
                }
                return;
            }
        }
@@ -1061,7 +1067,8 @@ public abstract class BiometricServiceBase extends SystemService
     * @param newClient the new client that wants to connect
     * @param initiatedByClient true for authenticate, remove and enroll
     */
    private void startClient(ClientMonitor newClient, boolean initiatedByClient) {
    @VisibleForTesting
    void startClient(ClientMonitor newClient, boolean initiatedByClient) {
        ClientMonitor currentClient = mCurrentClient;
        if (currentClient != null) {
            if (DEBUG) Slog.v(getTag(), "request stop current client " +
@@ -1124,18 +1131,27 @@ public abstract class BiometricServiceBase extends SystemService
            Slog.e(getTag(), "Trying to start null client!");
            return;
        }

        if (DEBUG) Slog.v(getTag(), "starting client "
                + mCurrentClient.getClass().getSuperclass().getSimpleName()
                + "(" + mCurrentClient.getOwnerString() + ")"
                + " targetUserId: " + mCurrentClient.getTargetUserId()
                + " currentUserId: " + mCurrentUserId
                + " cookie: " + cookie + "/" + mCurrentClient.getCookie());

        if (cookie != mCurrentClient.getCookie()) {
            Slog.e(getTag(), "Mismatched cookie");
            return;
        }

        int status = mCurrentClient.start();
        if (status == 0) {
            notifyClientActiveCallbacks(true);
        mCurrentClient.start();
        } else {
            mCurrentClient.onError(getHalDeviceId(), BIOMETRIC_ERROR_HW_UNAVAILABLE,
                    0 /* vendorCode */);
            removeClient(mCurrentClient);
        }
    }

    protected void removeClient(ClientMonitor client) {
+19 −2
Original line number Diff line number Diff line
@@ -17,6 +17,8 @@
package com.android.server.biometrics;

import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyLong;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.content.Context;
@@ -66,7 +68,6 @@ public class BiometricServiceBaseTest {

        @Override
        protected void updateActiveGroup(int userId, String clientPackage) {

        }

        @Override
@@ -96,7 +97,6 @@ public class BiometricServiceBaseTest {

        @Override
        protected void checkUseBiometricPermission() {

        }

        @Override
@@ -121,6 +121,8 @@ public class BiometricServiceBaseTest {
        }
    }

    private static final int CLIENT_COOKIE = 0xc00c1e;

    private BiometricServiceBase mBiometricServiceBase;

    @Mock
@@ -129,12 +131,17 @@ public class BiometricServiceBaseTest {
    private Resources mResources;
    @Mock
    private BiometricAuthenticator.Identifier mIdentifier;
    @Mock
    private ClientMonitor mClient;

    @Before
    public void setUp() {
        MockitoAnnotations.initMocks(this);

        when(mContext.getResources()).thenReturn(mResources);
        when(mResources.getString(anyInt())).thenReturn("");
        when(mClient.getCookie()).thenReturn(CLIENT_COOKIE);

        mBiometricServiceBase = new TestableBiometricServiceBase(mContext);
    }

@@ -142,4 +149,14 @@ public class BiometricServiceBaseTest {
    public void testHandleEnumerate_doesNotCrash_withNullClient() {
        mBiometricServiceBase.handleEnumerate(mIdentifier, 0 /* remaining */);
    }

    @Test
    public void testStartClient_sendsErrorAndRemovesClient_onNonzeroErrorCode() {
        when(mClient.start()).thenReturn(1);

        mBiometricServiceBase.startClient(mClient, false /* initiatedByClient */);

        verify(mClient).onError(anyLong(), anyInt(), anyInt());
        verify(mClient).destroy();
    }
}