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

Commit 98e742cf authored by Kevin Chyn's avatar Kevin Chyn Committed by Android (Google) Code Review
Browse files

Merge "Add wireframe for biometric TestApis"

parents b57b9245 fc26e8a0
Loading
Loading
Loading
Loading
+38 −0
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ package android {
    field public static final String REMOVE_TASKS = "android.permission.REMOVE_TASKS";
    field public static final String RESET_APP_ERRORS = "android.permission.RESET_APP_ERRORS";
    field public static final String SUSPEND_APPS = "android.permission.SUSPEND_APPS";
    field public static final String TEST_BIOMETRIC = "android.permission.TEST_BIOMETRIC";
    field public static final String TEST_MANAGE_ROLLBACKS = "android.permission.TEST_MANAGE_ROLLBACKS";
    field public static final String UPGRADE_RUNTIME_PERMISSIONS = "android.permission.UPGRADE_RUNTIME_PERMISSIONS";
    field public static final String WRITE_DEVICE_CONFIG = "android.permission.WRITE_DEVICE_CONFIG";
@@ -1223,6 +1224,35 @@ package android.graphics.drawable {

}

package android.hardware.biometrics {

  public class BiometricManager {
    method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession getTestSession();
  }

  public class BiometricTestSession implements java.lang.AutoCloseable {
    method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void authenticateReject(int, int);
    method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void authenticateSuccess(int, int);
    method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void close();
    method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void enableTestHal(int, boolean);
    method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void enrollFinish(int, int);
    method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void enrollStart(int, int);
    method @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public java.util.List<android.hardware.biometrics.SensorProperties> getSensorProperties();
    method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void internalCleanup(int, int);
    method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void notifyAcquired(int, int);
    method @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public void notifyError(int, int);
  }

  public class SensorProperties {
    method public int getSensorId();
    method public int getSensorStrength();
    field public static final int STRENGTH_CONVENIENCE = 0; // 0x0
    field public static final int STRENGTH_STRONG = 2; // 0x2
    field public static final int STRENGTH_WEAK = 1; // 0x1
  }

}

package android.hardware.camera2 {

  public abstract class CameraDevice implements java.lang.AutoCloseable {
@@ -1328,6 +1358,14 @@ package android.hardware.display {

}

package android.hardware.fingerprint {

  @Deprecated public class FingerprintManager {
    method @Deprecated @NonNull @RequiresPermission(android.Manifest.permission.TEST_BIOMETRIC) public android.hardware.biometrics.BiometricTestSession getTestSession();
  }

}

package android.hardware.hdmi {

  public final class HdmiControlManager {
+14 −0
Original line number Diff line number Diff line
@@ -16,14 +16,17 @@

package android.hardware.biometrics;

import static android.Manifest.permission.TEST_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC;
import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
import static android.Manifest.permission.WRITE_DEVICE_CONFIG;

import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.SystemApi;
import android.annotation.SystemService;
import android.annotation.TestApi;
import android.content.Context;
import android.os.RemoteException;
import android.security.keystore.KeyGenParameterSpec;
@@ -195,6 +198,17 @@ public class BiometricManager {
        mService = service;
    }

    /**
     * Retrieves a test session for BiometricManager/BiometricPrompt.
     * @hide
     */
    @TestApi
    @NonNull
    @RequiresPermission(TEST_BIOMETRIC)
    public BiometricTestSession getTestSession() {
        return null; // TODO(169459906)
    }

    /**
     * Determine if biometrics can be used. In other words, determine if
     * {@link BiometricPrompt} can be expected to be shown (hardware available, templates enrolled,
+202 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.hardware.biometrics;

import static android.Manifest.permission.TEST_BIOMETRIC;

import android.annotation.NonNull;
import android.annotation.RequiresPermission;
import android.annotation.TestApi;
import android.content.Context;
import android.os.RemoteException;
import android.util.Log;

import java.util.ArrayList;
import java.util.List;

/**
 * Common set of interfaces to test biometric-related APIs, including {@link BiometricPrompt} and
 * {@link android.hardware.fingerprint.FingerprintManager}.
 * @hide
 */
@TestApi
public class BiometricTestSession implements AutoCloseable {

    private static final String TAG = "TestManager";

    private final Context mContext;
    private final ITestService mTestService;

    /**
     * @hide
     */
    public BiometricTestSession(@NonNull Context context, @NonNull ITestService testService) {
        mContext = context;
        mTestService = testService;
    }

    /**
     * @return A list of {@link SensorProperties}
     */
    @NonNull
    @RequiresPermission(TEST_BIOMETRIC)
    public List<SensorProperties> getSensorProperties() {
        try {
            final List<SensorPropertiesInternal> internalProps =
                    mTestService.getSensorPropertiesInternal(mContext.getOpPackageName());
            final List<SensorProperties> props = new ArrayList<>();
            for (SensorPropertiesInternal internalProp : internalProps) {
                props.add(new SensorProperties(internalProp.sensorId, internalProp.sensorStrength));
            }
            return props;
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Switches the specified sensor to use a test HAL. In this mode, the framework will not invoke
     * any methods on the real HAL implementation. This allows the framework to test a substantial
     * portion of the framework code that would otherwise require human interaction. Note that
     * secure pathways such as HAT/Keystore are not testable, since they depend on the TEE or its
     * equivalent for the secret key.
     *
     * @param sensorId Sensor that this command applies to.
     * @param enableTestHal If true, enable testing with a fake HAL instead of the real HAL.
     */
    @RequiresPermission(TEST_BIOMETRIC)
    public void enableTestHal(int sensorId, boolean enableTestHal) {
        try {
            mTestService.enableTestHal(sensorId, enableTestHal);
        } catch (RemoteException e) {
            Log.e(TAG, "Remote exception", e);
        }
    }

    /**
     * Starts the enrollment process. This should generally be used when the test HAL is enabled.
     *
     * @param sensorId Sensor that this command applies to.
     * @param userId User that this command applies to.
     */
    @RequiresPermission(TEST_BIOMETRIC)
    public void enrollStart(int sensorId, int userId) {
        try {
            mTestService.enrollStart(sensorId, userId);
        } catch (RemoteException e) {
            Log.e(TAG, "Remote exception", e);
        }
    }

    /**
     * Finishes the enrollment process. Simulates the HAL's callback.
     *
     * @param sensorId Sensor that this command applies to.
     * @param userId User that this command applies to.
     */
    @RequiresPermission(TEST_BIOMETRIC)
    public void enrollFinish(int sensorId, int userId) {
        try {
            mTestService.enrollFinish(sensorId, userId);
        } catch (RemoteException e) {
            Log.e(TAG, "Remote exception", e);
        }
    }

    /**
     * Simulates a successful authentication, but does not provide a valid HAT.
     *
     * @param sensorId Sensor that this command applies to.
     * @param userId User that this command applies to.
     */
    @RequiresPermission(TEST_BIOMETRIC)
    public void authenticateSuccess(int sensorId, int userId) {
        try {
            mTestService.authenticateSuccess(sensorId, userId);
        } catch (RemoteException e) {
            Log.e(TAG, "Remote exception", e);
        }
    }

    /**
     * Simulates a rejected attempt.
     *
     * @param sensorId Sensor that this command applies to.
     * @param userId User that this command applies to.
     */
    @RequiresPermission(TEST_BIOMETRIC)
    public void authenticateReject(int sensorId, int userId) {
        try {
            mTestService.authenticateReject(sensorId, userId);
        } catch (RemoteException e) {
            Log.e(TAG, "Remote exception", e);
        }
    }

    /**
     * Simulates an acquired message from the HAL.
     *
     * @param sensorId Sensor that this command applies to.
     * @param userId User that this command applies to.
     */
    @RequiresPermission(TEST_BIOMETRIC)
    public void notifyAcquired(int sensorId, int userId) {
        try {
            mTestService.notifyAcquired(sensorId, userId);
        } catch (RemoteException e) {
            Log.e(TAG, "Remote exception", e);
        }
    }

    /**
     * Simulates an error message from the HAL.
     *
     * @param sensorId Sensor that this command applies to.
     * @param userId User that this command applies to.
     */
    @RequiresPermission(TEST_BIOMETRIC)
    public void notifyError(int sensorId, int userId) {
        try {
            mTestService.notifyError(sensorId, userId);
        } catch (RemoteException e) {
            Log.e(TAG, "Remote exception", e);
        }
    }

    /**
     * Matches the framework's cached enrollments against the HAL's enrollments. Any enrollment
     * that isn't known by both sides are deleted. This should generally be used when the test
     * HAL is disabled (e.g. to clean up after a test).
     *
     * @param sensorId Sensor that this command applies to.
     * @param userId User that this command applies to.
     */
    @RequiresPermission(TEST_BIOMETRIC)
    public void internalCleanup(int sensorId, int userId) {
        try {
            mTestService.internalCleanup(sensorId, userId);
        } catch (RemoteException e) {
            Log.e(TAG, "Remote exception", e);
        }
    }

    @Override
    @RequiresPermission(TEST_BIOMETRIC)
    public void close() {

    }
}
+57 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.hardware.biometrics;

import android.hardware.biometrics.SensorPropertiesInternal;

/**
 * A test service for FingerprintManager and BiometricPrompt.
 * @hide
 */
interface ITestService {
    // Returns a list of sensor properties supported by the interface.
    List<SensorPropertiesInternal> getSensorPropertiesInternal(String opPackageName);

    // Switches the specified sensor to use a test HAL. In this mode, the framework will not invoke
    // any methods on the real HAL implementation. This allows the framework to test a substantial
    // portion of the framework code that would otherwise require human interaction. Note that
    // secure pathways such as HAT/Keystore are not testable, since they depend on the TEE or its
    // equivalent for the secret key.
    void enableTestHal(int sensorId, boolean enableTestHal);

    // Starts the enrollment process. This should generally be used when the test HAL is enabled.
    void enrollStart(int sensorId, int userId);

    // Finishes the enrollment process. Simulates the HAL's callback.
    void enrollFinish(int sensorId, int userId);

    // Simulates a successful authentication, but does not provide a valid HAT.
    void authenticateSuccess(int sensorId, int userId);

    // Simulates a rejected attempt.
    void authenticateReject(int sensorId, int userId);

    // Simulates an acquired message from the HAL.
    void notifyAcquired(int sensorId, int userId);

    // Simulates an error message from the HAL.
    void notifyError(int sensorId, int userId);

    // Matches the framework's cached enrollments against the HAL's enrollments. Any enrollment
    // that isn't known by both sides are deleted. This should generally be used when the test
    // HAL is disabled (e.g. to clean up after a test).
    void internalCleanup(int sensorId, int userId);
}
+2 −5
Original line number Diff line number Diff line
@@ -17,6 +17,7 @@
package android.hardware.biometrics;

import android.annotation.IntDef;
import android.annotation.TestApi;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -25,19 +26,18 @@ import java.lang.annotation.RetentionPolicy;
 * The base class containing all modality-agnostic information.
 * @hide
 */
@TestApi
public class SensorProperties {
    /**
     * A sensor that meets the requirements for Class 1 biometrics as defined in the CDD. This does
     * not correspond to a public BiometricManager.Authenticators constant. Sensors of this strength
     * are not available to applications via the public API surface.
     * @hide
     */
    public static final int STRENGTH_CONVENIENCE = 0;

    /**
     * A sensor that meets the requirements for Class 2 biometrics as defined in the CDD.
     * Corresponds to BiometricManager.Authenticators.BIOMETRIC_WEAK.
     * @hide
     */
    public static final int STRENGTH_WEAK = 1;

@@ -46,7 +46,6 @@ public class SensorProperties {
     * Corresponds to BiometricManager.Authenticators.BIOMETRIC_STRONG.
     *
     * Notably, this is the only strength that allows generation of HardwareAuthToken(s).
     * @hide
     */
    public static final int STRENGTH_STRONG = 2;

@@ -70,7 +69,6 @@ public class SensorProperties {

    /**
     * @return The sensor's unique identifier.
     * @hide
     */
    public int getSensorId() {
        return mSensorId;
@@ -78,7 +76,6 @@ public class SensorProperties {

    /**
     * @return The sensor's strength.
     * @hide
     */
    @Strength
    public int getSensorStrength() {
Loading