From 1f7007465ddcacd4ff45f46ff8c4381507a96607 Mon Sep 17 00:00:00 2001 From: Zachary Iqbal Date: Tue, 24 Apr 2018 23:42:21 -0700 Subject: [PATCH] Added initial HIDL interface for the biometric face HAL. Notes: - Added a basic interface, a stub callback interface and a stubs for needed public types. - Ran make hidl-gen -j64 && hardware/interfaces/update-makefiles.sh to create build files for the interface. Bug: 79577138 Test: None added. This commit simply adds a new interface. Change-Id: I14b7238dd9ee1076f77c1b60117bdaa156a4f0f5 --- biometrics/face/1.0/Android.bp | 26 ++ biometrics/face/1.0/IBiometricsFace.hal | 191 +++++++++++++ .../1.0/IBiometricsFaceClientCallback.hal | 116 ++++++++ biometrics/face/1.0/types.hal | 255 ++++++++++++++++++ 4 files changed, 588 insertions(+) create mode 100644 biometrics/face/1.0/Android.bp create mode 100644 biometrics/face/1.0/IBiometricsFace.hal create mode 100644 biometrics/face/1.0/IBiometricsFaceClientCallback.hal create mode 100644 biometrics/face/1.0/types.hal diff --git a/biometrics/face/1.0/Android.bp b/biometrics/face/1.0/Android.bp new file mode 100644 index 0000000000..61bf247786 --- /dev/null +++ b/biometrics/face/1.0/Android.bp @@ -0,0 +1,26 @@ +// This file is autogenerated by hidl-gen -Landroidbp. + +hidl_interface { + name: "android.hardware.biometrics.face@1.0", + root: "android.hardware", + vndk: { + enabled: true, + }, + srcs: [ + "types.hal", + "IBiometricsFace.hal", + "IBiometricsFaceClientCallback.hal", + ], + interfaces: [ + "android.hidl.base@1.0", + ], + types: [ + "FaceAcquiredInfo", + "FaceError", + "OptionalUint64", + "Status", + "UserHandle", + ], + gen_java: true, +} + diff --git a/biometrics/face/1.0/IBiometricsFace.hal b/biometrics/face/1.0/IBiometricsFace.hal new file mode 100644 index 0000000000..fbdb210694 --- /dev/null +++ b/biometrics/face/1.0/IBiometricsFace.hal @@ -0,0 +1,191 @@ +/* + * Copyright (C) 2018 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.face@1.0; + +import IBiometricsFaceClientCallback; + +// TODO(b/78538290): Update comments with state machine transitions when ready. +// TODO(b/78537981): Update comments with callback interaction contract. +// TODO(b/79496983): Update comments with status returns fully enumerated. +/** + * The HAL interface for biometric face authentication. + */ +interface IBiometricsFace { + + /** + * Sets the current client callback. + * + * Registers a user function that must receive notifications from the HAL. + * There is usually only one client (FaceService). This call must block + * if the HAL state machine is in busy state until the HAL leaves the + * busy state. + * + * All callback methods pass a deviceId to differentiate callback + * invocations in the case where multiple sensors exist. + * + * @param clientCallback The client defined callback to register. + * @return result, with its "value" parameter representing a "deviceId", + * which must be unique for a given sensor. + */ + @callflow(next={"setActiveUser"}) + @entry + setCallback(IBiometricsFaceClientCallback clientCallback) + generates (OptionalUint64 result); + + /** + * Sets the active user, which all subsequent HAL operations are applied to. + * + * HAL service implementors must ensure that operations are restricted to + * the given user. Clients must not call any part of this interface, except + * for setCallback(), without first having set an active user. The + * implementation is responsible for cancelling the current operation and + * returning to the idle state. Calling this method with the same userId + * should have no effect on the state machine. + * + * @param userId A non-negative user identifier that must be unique and + * persistent for a given user. + * @param storePath filesystem path to the template storage directory. + */ + @callflow(next={"authenticate", "preEnroll", "enumerate", "remove"}) + setActiveUser(int32_t userId, string storePath) generates (Status status); + + /** + * Begins a pre-enrollment request. + * + * Generates a unique and cryptographically secure random token used to + * indicate the start of an enrollment transaction. preEnroll() and + * postEnroll() specify a pin/pattern/password cleared time window where + * enrollment is allowed. + * + * preEnroll() generates a challenge which must then be wrapped by the + * gatekeeper after verifying a successful strong authentication attempt, + * which generates a Hardware Authentication Token. The challenge prevents + * spoofing and replay attacks and ensures that we only update a user’s face + * template if the operation was preceded by some kind of strong credential + * confirmation (e.g. device password). + * + * @return result, with its "value" parameter representing a "challenge": a + * unique and cryptographically secure random token. + */ + @callflow(next={"enroll", "postEnroll"}) + preEnroll() generates (OptionalUint64 result); + + /** + * Enrolls a user's face. + * + * Note that this interface permits implementations where multiple faces can + * be enrolled for a single user. However, allowing multiple faces to be + * enrolled can be a severe security vulnerability and hence, most + * implementations must ensure that only a single face be enrolled at a + * given time. Multi-enrollment must only be used where there is a clear + * necessity for a shared use case, e.g. TVs or cars. + * + * Note that the Hardware Authentication Token must still be valid after + * this call, and must be explicitly invalidated by a call to postEnroll(). + * This allows clients to immediately reattempt enrollment (for example, if + * a user wasn’t satisfied with their enrollment) without having to go + * through another strong authentication flow. + * + * This method triggers the IBiometricsFaceClientCallback#onEnrollResult() + * method. + * + * @param hat A valid Hardware Authentication Token, generated as a result + * of a preEnroll() challenge being wrapped by the gatekeeper after a + * sucessful strong authentication request. + * @param timeoutSec A timeout in seconds, after which this enrollment + * attempt is cancelled. Note that the client still needs to + * call postEnroll() to terminate the enrollment session. + * @return status The status of this method call. + */ + @callflow(next={"cancel", "enroll", "postEnroll", "remove"}) + enroll(vec hat, uint32_t timeoutSec) generates (Status status); + + /** + * Finishes the enrollment session and invalidates the challenge generated + * by preEnroll(). + * + * Clients must call this method once enrollment is complete, and the user's + * face template no longer needs to be updated. + * + * @return status The status of this method call. + */ + @callflow(next={"authenticate", "setActiveUser", "enumerate", "remove"}) + postEnroll() generates (Status status); + + /** + * Returns an identifier associated with the current face set. + * + * The authenticator ID must change whenever a new face is enrolled. The + * authenticator ID must not be changed when a face is deleted. The + * authenticator ID must be an entropy-encoded random number which all + * current templates are tied to. The authenticator ID must be immutable + * outside of an active enrollment window to prevent replay attacks. + * + * @return result, with its value parameter representing an + * "authenticatorId": an identifier associated to the user's current + * face enrollment. + */ + @callflow(next={"authenticate"}) + getAuthenticatorId() generates (OptionalUint64 result); + + /** + * Cancels a pending enrollment or authentication request. + * + * @return status The status of this method call. + */ + @callflow(next={"authenticate", "enroll", "enumerate", "remove", + "setActiveUser"}) + cancel() generates (Status status); + + /** + * Enumerates all face templates associated with the active user. + * + * The onEnumerate() callback method is invoked once for each face template + * found. + * + * @return status The status of this method call. + */ + @callflow(next={"remove", "enroll", "authenticate", "setActiveUser"}) + enumerate() generates (Status status); + + /** + * Removes a face template or all face templates associated with the active + * user. + * + * This method triggers the IBiometricsFaceClientCallback#onRemoved() method. + * + * @param faceId The id correpsonding to the face to be removed; or 0 if all + * faces are to be removed. + * @return status The status of this method call. + */ + @callflow(next={"enumerate", "authenticate", "cancel", "getAuthenticatorId", + "setActiveUser"}) + remove(uint32_t faceId) generates (Status status); + + /** + * Authenticates the active user. + * + * An optional operationId can be specified as a token from the transaction + * being authorized. + * + * @param operationId A non-zero operation id associated with a crypto + * object instance; or 0 if not being used. + * @return status The status of this method call. + */ + @callflow(next={"cancel", "preEnroll", "remove"}) + authenticate(uint64_t operationId) generates (Status status); +}; diff --git a/biometrics/face/1.0/IBiometricsFaceClientCallback.hal b/biometrics/face/1.0/IBiometricsFaceClientCallback.hal new file mode 100644 index 0000000000..93848c57bb --- /dev/null +++ b/biometrics/face/1.0/IBiometricsFaceClientCallback.hal @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2018 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.face@1.0; + +/** + * This callback interface is used by clients to recieve updates from the face + * HAL. + */ +interface IBiometricsFaceClientCallback { + + /** + * A callback invoked when one enrollment step has been completed. + * + * @param deviceId A unique id associated with the HAL implementation + * service that processed this enrollment step. + * @param faceId The id of the face template being enrolled. + * @param userId The active user id for the template being enrolled. + * @param remaining The number of remaining steps before enrolllment is + * complete or 0 if enrollment has completed successfully. + */ + oneway onEnrollResult(uint64_t deviceId, uint32_t faceId, int32_t userId, + uint32_t remaining); + + /** + * A callback invoked when a face has been successfully authenticated. + * + * @param deviceId A unique id associated with the HAL implementation + * service that processed this autentication attempt. + * @param faceId The id of the face template that passed the authentication + * challenge. + * @param userId The active user id for the authenticated face. + * @param token The hardware authentication token associated with this + * authenticate operation. + */ + oneway onAuthenticated(uint64_t deviceId, uint32_t faceId, int32_t userId, + vec token); + + /** + * A callback invoked when a face is acquired. + * + * If a non-critical, recoverable error occurs during an enrollment or + * authentication attempt, the HAL implementation must invoke this callback + * to allow clients to inform the user that some actionable change must be + * made. + * + * @param deviceId A unique id associated with the HAL implementation + * service that acquired a face. + * @param userId The id of the active user associated with the attempted + * face acquisition. + * @param acquiredInfo A message about the quality of the acquired image. + * @param vendorCode An optional vendor-specific message. This is only valid + * when acquiredInfo == FaceAcquiredInfo.VENDOR. This message is opaque + * to the framework, and vendors must provide code to handle it. For + * example this can be used to guide enrollment in Settings or provide + * a message during authentication that is vendor-specific. The vendor + * is expected to provide help strings to cover all known values. + */ + oneway onAcquired(uint64_t deviceId, int32_t userId, + FaceAcquiredInfo acquiredInfo, int32_t vendorCode); + + /** + * A callback invoked when an error has occured. + * + * @param deviceId A unique id associated with the HAL implementation + * service where this error occured. + * @param userId The id of the active user when the error occured, or + * UserHandle::NONE if an active user had not been set yet. + * @param error A message about the error that occurred. + * @param vendorCode An optional, vendor-speicifc error message. Only valid + * when error == FaceError.VENDOR. This message is opaque to the + * framework, and vendors must provide code to handle it. For example, + * this scan be used to show the user an error message specific to the + * device. The vendor is expected to provide error strings to cover + * all known values. + */ + oneway onError(uint64_t deviceId, int32_t userId, FaceError error, + int32_t vendorCode); + + /** + * A callback invoked when a face template has been removed. + * + * @param deviceId A unique id associated with the HAL implementation + * service that processed this removal. + * @param faceId The id of the face template that was removed. + * @param userId The active user id for the removed face template. + * @param remaining The number of face templates remaining after this + * removal, or 0 if there are no more. + */ + oneway onRemoved(uint64_t deviceId, uint32_t faceId, int32_t userId, + uint32_t remaining); + + /** + * A callback invoked to enumerate all current face templates. + * + * @param deviceId A unique id associated with the HAL implementation + * service that processed this enumeration. + * @param faceIds A list of ids of all currently enrolled face templates. + * @param userId The active user id for the enumerated face template. + */ + oneway onEnumerate(uint64_t deviceId, vec faceIds, + int32_t userId); +}; diff --git a/biometrics/face/1.0/types.hal b/biometrics/face/1.0/types.hal new file mode 100644 index 0000000000..08af91907b --- /dev/null +++ b/biometrics/face/1.0/types.hal @@ -0,0 +1,255 @@ +/* + * Copyright (C) 2018 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.face@1.0; + +/* + * In the event setActiveUser is not called, all error messages will return + * this userId. + */ +enum UserHandle : int32_t { + NONE = -1 +}; + +/** + * Status codes returned directly by the HIDL method calls upon critical errors + * where the callback cannot be invoked. Most errors should sent through the + * onError callback using one of the FaceErrors below. + */ +enum Status : uint32_t { + /** + * The method was invoked successfully. + */ + OK = 0, + + /** + * One of the arguments to the method call is invalid. + */ + ILLEGAL_ARGUMENT = 1, + + /** + * This face HAL does not support this operation. + */ + OPERATION_NOT_SUPPORTED = 2, + + /** + * The HAL has encountered an internal error and cannot complete the request. + */ + INTERNAL_ERROR = 3 +}; + +/** + * Face errors represent events that can't be immediately recovered by user + * intervention. These are returned in the onError callback. + * + * Upon receiving a face error, clients must terminate the current operation and + * notify the user where possible. + */ +enum FaceError : int32_t { + + /** + * A hardware error has occured that cannot be resolved. Try again later. + */ + HW_UNAVAILABLE = 1, + + /** + * The current enroll or authenticate operation could not be completed; + * the sensor was unable to process the current image. + */ + UNABLE_TO_PROCESS = 2, + + /** + * The current operation took too long to complete. This is intended to + * prevent programs from blocking the face HAL indefinitely. The timeout is + * framework and sensor-specific, but is generally on the order of 30 + * seconds. + */ + TIMEOUT = 3, + + /** + * The current operation could not be completed because there is not enough + * storage space remaining to do so. + */ + NO_SPACE = 4, + + /** + * The current operation has been cancelled. This may happen if a new + * request (authenticate, remove) is initiated while an on-going operation + * is in progress, or if cancel() was called. + */ + CANCELED = 5, + + /** + * The current remove operation could not be completed; the face template + * provided could not be removed. + */ + UNABLE_TO_REMOVE = 6, + + /** + * Face authentication is locked out due to too many unsuccessful attempts. + */ + LOCKOUT = 7, + + /** + * Used to enable a vendor-specific error message. + */ + VENDOR = 8, +}; + +/** + * Face acquisition information provides feedback for the current enrollment + * or authentication operation. + * + * This information indicates that the user can take immediate action to resolve + * an issue, and clients must ensure that this information is surfaced to the + * user. + */ +enum FaceAcquiredInfo : int32_t { + + /** + * The face acquired was good; no further user interaction is necessary. + */ + GOOD = 0, + + /** + * The face data acquired was too noisy or did not have sufficient detail. + * This is a catch-all for all acquisition errors not captured by the other + * constants. + */ + INSUFFICIENT = 1, + + /** + * Because there was too much ambient light, the captured face data was too + * bright. It's reasonable to return this after multiple + * FaceAcquiredInfo.INSUFFICIENT. + * + * The user is expected to take action to retry the operation in better + * lighting conditions when this is returned. + */ + TOO_BRIGHT = 2, + + /** + * Because there was not enough illumination, the captured face data was too + * dark. It's reasonable to return this after multiple + * FaceAcquiredInfo.INSUFFICIENT. + * + * The user is expected to take action to retry the operation in better + * lighting conditions when this is returned. + */ + TOO_DARK = 3, + + /** + * The detected face is too close to the sensor, and the image cannot be + * processed. + * + * The user is expected to be informed to move further from the sensor when + * this is returned. + */ + TOO_CLOSE = 4, + + /** + * The detected face is too small, as the user might be too far away from + * the sensor. + * + * The user is expected to be informed to move closer to the sensor when + * this is returned. + */ + TOO_FAR = 5, + + /** + * Only the upper part of the face was detected. The sensor's field of view + * is too high. + * + * The user should be informed to move up with respect to the sensor when + * this is returned. + */ + FACE_TOO_HIGH = 6, + + /** + * Only the lower part of the face was detected. The sensor's field of view + * is too low. + * + * The user should be informed to move down with respect to the sensor when + * this is returned. + */ + FACE_TOO_LOW = 7, + + /** + * Only the right part of the face was detected. The sensor's field of view + * is too far right. + * + * The user should be informed to move to the right with respect to the + * sensor when this is returned. + */ + FACE_TOO_RIGHT = 8, + + /** + * Only the left part of the face was detected. The sensor's field of view + * is too far left. + * + * The user should be informed to move to the left with respect to the + * sensor when this is returned. + */ + FACE_TOO_LEFT = 9, + + /** + * The user's face was directed away from the sensor. The user should be + * informed to face the sensor when this is returned. + */ + POOR_GAZE = 10, + + /** + * No face was detected within the sensor's field of view. + * + * The user should be informed to point the sensor to a face when this is + * returned. + */ + NOT_DETECTED = 11, + + /** + * Too much motion was detected. + * + * The user should be informed to keep their face steady relative to the + * sensor. + */ + TOO_MUCH_MOTION = 12, + + /** + * The sensor needs to be recalibrated. + */ + RECALIBRATE = 13, + + /** + * Used to enable a vendor-specific acquisition message. + */ + VENDOR = 14 +}; + +/** + * Result structure with an additional uint64_t field. See documentation in + * setCallback(), preEnroll(), and getAuthenticatorId() for usage of the value. + */ +struct OptionalUint64 { + /** + * The return status. + */ + Status status; + + /** + * This value is only meaningful if status is OK. + */ + uint64_t value; +};