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

Commit b08c6432 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Automerger Merge Worker
Browse files

Merge "RemovalClient handles null authenticator" into tm-dev am: f7b81da3

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/17033636

Change-Id: Ife45b9744a3f6e42a1dd50d0b571dd35710f4d66
parents 208a7d31 f7b81da3
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -123,7 +123,8 @@ public class ClientMonitorCallbackConverter {
        }
    }

    void onRemoved(BiometricAuthenticator.Identifier identifier, int remaining)
    /** Called when a user has been removed. */
    public void onRemoved(BiometricAuthenticator.Identifier identifier, int remaining)
            throws RemoteException {
        if (mFaceServiceReceiver != null) {
            mFaceServiceReceiver.onRemoved((Face) identifier, remaining);
+19 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package com.android.server.biometrics.sensors;
import android.annotation.NonNull;
import android.content.Context;
import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Slog;
@@ -71,6 +72,24 @@ public abstract class RemovalClient<S extends BiometricAuthenticator.Identifier,

    @Override
    public void onRemoved(@NonNull BiometricAuthenticator.Identifier identifier, int remaining) {
        // This happens when we have failed to remove a biometric.
        if (identifier == null) {
            Slog.e(TAG, "identifier was null, skipping onRemove()");
            try {
                if (getListener() != null) {
                    getListener().onError(getSensorId(), getCookie(),
                            BiometricConstants.BIOMETRIC_ERROR_UNABLE_TO_REMOVE,
                            0 /* vendorCode */);
                } else {
                    Slog.e(TAG, "Error, listener was null, not sending onError callback");
                }
            } catch (RemoteException e) {
                Slog.w(TAG, "Failed to send error to client for onRemoved", e);
            }
            mCallback.onClientFinished(this, false /* success */);
            return;
        }

        Slog.d(TAG, "onRemoved: " + identifier.getBiometricId() + " remaining: " + remaining);
        mBiometricUtils.removeBiometricForUser(getContext(), getTargetUserId(),
                identifier.getBiometricId());
+124 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2022 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.biometrics.sensors.face.aidl;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import android.hardware.biometrics.BiometricAuthenticator;
import android.hardware.biometrics.BiometricConstants;
import android.hardware.biometrics.face.ISession;
import android.hardware.face.Face;
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.testing.TestableContext;

import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;

import com.android.server.biometrics.log.BiometricContext;
import com.android.server.biometrics.log.BiometricLogger;
import com.android.server.biometrics.sensors.BiometricUtils;
import com.android.server.biometrics.sensors.ClientMonitorCallback;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;

import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;

import java.util.HashMap;
import java.util.Map;

@Presubmit
@SmallTest
public class FaceRemovalClientTest {

    private static final int USER_ID = 12;

    @Rule
    public final TestableContext mContext = new TestableContext(
            InstrumentationRegistry.getInstrumentation().getTargetContext(), null);
    @Rule
    public final MockitoRule mockito = MockitoJUnit.rule();

    @Mock
    private ISession mHal;
    @Mock
    private IBinder mToken;
    @Mock
    private ClientMonitorCallbackConverter mClientMonitorCallbackConverter;
    @Mock
    private BiometricLogger mBiometricLogger;
    @Mock
    private BiometricContext mBiometricContext;
    @Mock
    private ClientMonitorCallback mCallback;
    @Mock
    private Sensor.HalSessionCallback mHalSessionCallback;
    @Mock
    private BiometricUtils<Face> mUtils;
    @Mock
    private BiometricAuthenticator.Identifier mIdentifier;
    private Map<Integer, Long> mAuthenticatorIds = new HashMap<Integer, Long>();

    @Before
    public void setup() {
        when(mBiometricContext.updateContext(any(), anyBoolean())).thenAnswer(
                i -> i.getArgument(0));
    }

    @Test
    public void testFaceRemovalClient() throws RemoteException {
        final int authenticatorId = 1;
        int[] authenticatorIds = new int[]{authenticatorId};
        final FaceRemovalClient client = createClient(1, authenticatorIds);
        when(mIdentifier.getBiometricId()).thenReturn(authenticatorId);
        client.start(mCallback);
        verify(mHal).removeEnrollments(authenticatorIds);
        client.onRemoved(mIdentifier, 0 /* remaining */);
        verify(mClientMonitorCallbackConverter).onRemoved(
                eq(mIdentifier) /* identifier */, eq(0) /* remaining */);
        verify(mCallback).onClientFinished(client, true);
    }

    @Test
    public void clientSendsErrorWhenHALFailsToRemoveEnrollment() throws RemoteException {
        final FaceRemovalClient client = createClient(1, new int[0]);
        client.start(mCallback);
        client.onRemoved(null, 0 /* remaining */);
        verify(mClientMonitorCallbackConverter).onError(eq(5) /* sensorId */, anyInt(),
                eq(BiometricConstants.BIOMETRIC_ERROR_UNABLE_TO_REMOVE), eq(0) /* vendorCode*/);
        verify(mCallback).onClientFinished(client, false);
    }

    private FaceRemovalClient createClient(int version, int[] biometricIds) throws RemoteException {
        when(mHal.getInterfaceVersion()).thenReturn(version);
        final AidlSession aidl = new AidlSession(version, mHal, USER_ID, mHalSessionCallback);
        return new FaceRemovalClient(mContext, () -> aidl, mToken,
                mClientMonitorCallbackConverter, biometricIds, USER_ID,
                "own-it", mUtils /* utils */, 5 /* sensorId */, mBiometricLogger, mBiometricContext,
                mAuthenticatorIds);
    }
}