Merge ab/7633965

Bug: 169893837
Merged-In: I07cf1825c23e2467852d5cd93436eb9dee23b408
Change-Id: Ie9a09f85d7b24b031cb6869429a33ff1eeb84687
This commit is contained in:
The Android Open Source Project
2021-08-12 12:03:37 -07:00
committed by Xin Li
67 changed files with 1785 additions and 655 deletions

View File

@@ -332,18 +332,21 @@ TEST_P(AudioPrimaryHidlTest, setMode) {
#endif
for (int mode : {-2, -1, maxMode + 1}) {
ASSERT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(AudioMode(mode)))
EXPECT_RESULT(Result::INVALID_ARGUMENTS, getDevice()->setMode(AudioMode(mode)))
<< "mode=" << mode;
}
// Test valid values
for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
AudioMode::NORMAL /* Make sure to leave the test in normal mode */}) {
ASSERT_OK(getDevice()->setMode(mode)) << "mode=" << toString(mode);
}
// AudioMode::CALL_SCREEN as support is optional
#if MAJOR_VERSION >= 6
ASSERT_RESULT(okOrNotSupportedOrInvalidArgs, getDevice()->setMode(AudioMode::CALL_SCREEN));
EXPECT_RESULT(okOrNotSupportedOrInvalidArgs, getDevice()->setMode(AudioMode::CALL_SCREEN));
#endif
// Test valid values
for (AudioMode mode : {AudioMode::IN_CALL, AudioMode::IN_COMMUNICATION, AudioMode::RINGTONE,
AudioMode::NORMAL}) {
EXPECT_OK(getDevice()->setMode(mode)) << "mode=" << toString(mode);
}
// Make sure to leave the test in normal mode
getDevice()->setMode(AudioMode::NORMAL);
}
TEST_P(AudioPrimaryHidlTest, setBtHfpSampleRate) {

View File

@@ -2269,48 +2269,74 @@ TEST_P(EvsHidlTest, CameraStreamExternalBuffering) {
// Acquire the graphics buffer allocator
android::GraphicBufferAllocator& alloc(android::GraphicBufferAllocator::get());
const auto usage = GRALLOC_USAGE_HW_TEXTURE |
GRALLOC_USAGE_SW_READ_RARELY |
GRALLOC_USAGE_SW_WRITE_OFTEN;
const auto usage =
GRALLOC_USAGE_HW_TEXTURE | GRALLOC_USAGE_SW_READ_RARELY | GRALLOC_USAGE_SW_WRITE_OFTEN;
const auto format = HAL_PIXEL_FORMAT_RGBA_8888;
const auto width = 640;
const auto height = 360;
// Allocate buffers to use
hidl_vec<BufferDesc> buffers;
buffers.resize(kBuffersToHold);
for (auto i = 0; i < kBuffersToHold; ++i) {
unsigned pixelsPerLine;
buffer_handle_t memHandle = nullptr;
android::status_t result = alloc.allocate(width,
height,
format,
1,
usage,
&memHandle,
&pixelsPerLine,
0,
"EvsApp");
if (result != android::NO_ERROR) {
LOG(ERROR) << __FUNCTION__ << " failed to allocate memory.";
} else {
BufferDesc buf;
AHardwareBuffer_Desc* pDesc =
reinterpret_cast<AHardwareBuffer_Desc *>(&buf.buffer.description);
pDesc->width = width;
pDesc->height = height;
pDesc->layers = 1;
pDesc->format = format;
pDesc->usage = usage;
pDesc->stride = pixelsPerLine;
buf.buffer.nativeHandle = memHandle;
buf.bufferId = i; // Unique number to identify this buffer
buffers[i] = buf;
}
}
uint32_t width = 640;
uint32_t height = 360;
camera_metadata_entry_t streamCfgs;
// Test each reported camera
for (auto&& cam: cameraInfo) {
for (auto&& cam : cameraInfo) {
bool foundCfg = false;
if (!find_camera_metadata_entry(reinterpret_cast<camera_metadata_t*>(cam.metadata.data()),
ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS,
&streamCfgs)) {
// Stream configurations are found in metadata
RawStreamConfig* ptr = reinterpret_cast<RawStreamConfig*>(streamCfgs.data.i32);
LOG(DEBUG) << __LINE__ << " start searching " << streamCfgs.count;
for (unsigned idx = 0; idx < streamCfgs.count; idx++) {
LOG(DEBUG) << "ptr->direction= " << ptr->direction
<< " ptr->format= " << ptr->format;
if (ptr->direction == ANDROID_SCALER_AVAILABLE_STREAM_CONFIGURATIONS_OUTPUT &&
ptr->format == HAL_PIXEL_FORMAT_RGBA_8888) {
width = ptr->width;
height = ptr->height;
foundCfg = true;
// Always use the 1st available configuration
break;
}
++ptr;
}
}
if (!foundCfg) {
LOG(INFO) << "No configuration found. Use default stream configurations.";
}
// Allocate buffers to use
hidl_vec<BufferDesc> buffers;
buffers.resize(kBuffersToHold);
for (auto i = 0; i < kBuffersToHold; ++i) {
unsigned pixelsPerLine;
buffer_handle_t memHandle = nullptr;
android::status_t result =
alloc.allocate(width, height, format, 1, usage, &memHandle, &pixelsPerLine, 0,
"CameraStreamExternalBufferingTest");
if (result != android::NO_ERROR) {
LOG(ERROR) << __FUNCTION__ << " failed to allocate memory.";
// Release previous allocated buffers
for (auto j = 0; j < i; j++) {
alloc.free(buffers[i].buffer.nativeHandle);
}
return;
} else {
BufferDesc buf;
AHardwareBuffer_Desc* pDesc =
reinterpret_cast<AHardwareBuffer_Desc*>(&buf.buffer.description);
pDesc->width = width;
pDesc->height = height;
pDesc->layers = 1;
pDesc->format = format;
pDesc->usage = usage;
pDesc->stride = pixelsPerLine;
buf.buffer.nativeHandle = memHandle;
buf.bufferId = i; // Unique number to identify this buffer
buffers[i] = buf;
}
}
bool isLogicalCam = false;
getPhysicalCameraIds(cam.v1.cameraId, isLogicalCam);
@@ -2374,13 +2400,12 @@ TEST_P(EvsHidlTest, CameraStreamExternalBuffering) {
// Explicitly release the camera
pEnumerator->closeCamera(pCam);
activeCameras.clear();
// Release buffers
for (auto& b : buffers) {
alloc.free(b.buffer.nativeHandle);
}
buffers.resize(0);
}
// Release buffers
for (auto& b : buffers) {
alloc.free(b.buffer.nativeHandle);
}
buffers.resize(0);
}

View File

@@ -124,7 +124,7 @@ const ConfigDeclaration kVehicleProperties[]{
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::STATIC,
},
.initialValue = {.floatValues = {1776, 4950, 2008, 2140, 2984, 1665, 1667, 11800}}},
.initialValue = {.int32Values = {1776, 4950, 2008, 2140, 2984, 1665, 1667, 11800}}},
{.config =
{
.prop = toInt(VehicleProperty::PERF_VEHICLE_SPEED),
@@ -174,7 +174,7 @@ const ConfigDeclaration kVehicleProperties[]{
.prop = toInt(VehicleProperty::PERF_ODOMETER),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::CONTINUOUS,
.minSampleRate = 0.0f,
.minSampleRate = 1.0f,
.maxSampleRate = 10.0f,
},
.initialValue = {.floatValues = {0.0f}}},
@@ -183,7 +183,7 @@ const ConfigDeclaration kVehicleProperties[]{
.prop = toInt(VehicleProperty::PERF_STEERING_ANGLE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::CONTINUOUS,
.minSampleRate = 0.0f,
.minSampleRate = 1.0f,
.maxSampleRate = 10.0f,
},
.initialValue = {.floatValues = {0.0f}}},
@@ -192,7 +192,7 @@ const ConfigDeclaration kVehicleProperties[]{
.prop = toInt(VehicleProperty::PERF_REAR_STEERING_ANGLE),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::CONTINUOUS,
.minSampleRate = 0.0f,
.minSampleRate = 1.0f,
.maxSampleRate = 10.0f,
},
.initialValue = {.floatValues = {0.0f}}},
@@ -213,7 +213,7 @@ const ConfigDeclaration kVehicleProperties[]{
.prop = toInt(VehicleProperty::FUEL_LEVEL),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::CONTINUOUS,
.minSampleRate = 0.0f,
.minSampleRate = 1.0f,
.maxSampleRate = 100.0f,
},
.initialValue = {.floatValues = {15000.0f}}},
@@ -231,7 +231,7 @@ const ConfigDeclaration kVehicleProperties[]{
.prop = toInt(VehicleProperty::EV_BATTERY_LEVEL),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::CONTINUOUS,
.minSampleRate = 0.0f,
.minSampleRate = 1.0f,
.maxSampleRate = 100.0f,
},
.initialValue = {.floatValues = {150000.0f}}},
@@ -328,6 +328,11 @@ const ConfigDeclaration kVehicleProperties[]{
.prop = toInt(VehicleProperty::CURRENT_GEAR),
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.configArray = {(int)VehicleGear::GEAR_PARK,
(int)VehicleGear::GEAR_NEUTRAL,
(int)VehicleGear::GEAR_REVERSE, (int)VehicleGear::GEAR_1,
(int)VehicleGear::GEAR_2, (int)VehicleGear::GEAR_3,
(int)VehicleGear::GEAR_4, (int)VehicleGear::GEAR_5},
},
.initialValue = {.int32Values = {toInt(VehicleGear::GEAR_PARK)}}},
@@ -1072,8 +1077,8 @@ const ConfigDeclaration kVehicleProperties[]{
.access = VehiclePropertyAccess::READ,
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
},
.initialValue = {.int32Values = {0 /* Off */, -1, -1, -1, -1 /* Bounds */,
-1, -1, -1, -1 /* Insets */}},
.initialValue = {.int32Values = {0 /* Off */, -1, -1, -1, -1 /* Bounds */, -1, -1,
-1, -1 /* Insets */}},
},
{
.config =
@@ -1126,9 +1131,9 @@ const ConfigDeclaration kVehicleProperties[]{
.changeMode = VehiclePropertyChangeMode::ON_CHANGE,
.configArray = {0, 0, 0, 11, 0, 0, 0, 0, 16},
},
.initialValue = {.int32Values = {0 /* Off */, -1, -1, -1, -1 /* Bounds */,
-1, -1, -1, -1 /* Insets */,
0 /* ClusterHome */, -1 /* ClusterNone */}},
.initialValue = {.int32Values = {0 /* Off */, -1, -1, -1, -1 /* Bounds */, -1, -1,
-1, -1 /* Insets */, 0 /* ClusterHome */,
-1 /* ClusterNone */}},
},
{
.config =

View File

@@ -1 +1 @@
945de3635b7f5a09244820eef56035c92fdbd324
3b10f5094c5af9fe551093597fab007d1e148256

View File

@@ -37,7 +37,7 @@ interface ISession {
void generateChallenge();
void revokeChallenge(in long challenge);
android.hardware.biometrics.face.EnrollmentStageConfig[] getEnrollmentConfig(in android.hardware.biometrics.face.EnrollmentType enrollmentType);
android.hardware.biometrics.common.ICancellationSignal enroll(in android.hardware.keymaster.HardwareAuthToken hat, in android.hardware.biometrics.face.EnrollmentType type, in android.hardware.biometrics.face.Feature[] features, in android.hardware.common.NativeHandle previewSurface);
android.hardware.biometrics.common.ICancellationSignal enroll(in android.hardware.keymaster.HardwareAuthToken hat, in android.hardware.biometrics.face.EnrollmentType type, in android.hardware.biometrics.face.Feature[] features, in @nullable android.hardware.common.NativeHandle previewSurface);
android.hardware.biometrics.common.ICancellationSignal authenticate(in long operationId);
android.hardware.biometrics.common.ICancellationSignal detectInteraction();
void enumerateEnrollments();

View File

@@ -37,7 +37,7 @@ interface ISession {
void generateChallenge();
void revokeChallenge(in long challenge);
android.hardware.biometrics.face.EnrollmentStageConfig[] getEnrollmentConfig(in android.hardware.biometrics.face.EnrollmentType enrollmentType);
android.hardware.biometrics.common.ICancellationSignal enroll(in android.hardware.keymaster.HardwareAuthToken hat, in android.hardware.biometrics.face.EnrollmentType type, in android.hardware.biometrics.face.Feature[] features, in android.hardware.common.NativeHandle previewSurface);
android.hardware.biometrics.common.ICancellationSignal enroll(in android.hardware.keymaster.HardwareAuthToken hat, in android.hardware.biometrics.face.EnrollmentType type, in android.hardware.biometrics.face.Feature[] features, in @nullable android.hardware.common.NativeHandle previewSurface);
android.hardware.biometrics.common.ICancellationSignal authenticate(in long operationId);
android.hardware.biometrics.common.ICancellationSignal detectInteraction();
void enumerateEnrollments();

View File

@@ -19,6 +19,15 @@ package android.hardware.biometrics.face;
@VintfStability
@Backing(type="byte")
enum EnrollmentType {
/**
* Default enrollment type.
*/
DEFAULT,
/**
* Enrollment type for people with limited vision or mobility. For example,
* enrollment of this type will not ask the user to move their head or
* look directly at the device.
*/
ACCESSIBILITY,
}

View File

@@ -16,4 +16,23 @@
package android.hardware.biometrics.face;
@VintfStability @Backing(type="byte") enum FaceSensorType { UNKNOWN, RGB, IR }
@VintfStability
@Backing(type="byte")
enum FaceSensorType {
/**
* Placeholder value used for default initialization of FaceSensorType.
* This value means FaceSensorType wasn't explicitly initialized and must
* be discarded by the recipient.
*/
UNKNOWN,
/**
* The face sensor is an RGB camera.
*/
RGB,
/**
* The face sensor is an infrared camera.
*/
IR,
}

View File

@@ -25,28 +25,30 @@ interface IFace {
/**
* getSensorProps:
*
* @return A list of properties for all face sensors available to the HAL.
* @return A list of properties for all of the face sensors supported by the HAL.
*/
SensorProps[] getSensorProps();
/**
* createSession:
*
* Creates a session that can be used by the framework to perform operations such as
* enroll, authenticate, etc. for the given sensorId and userId.
* Creates an instance of ISession that can be used by the framework to perform operations such
* as ISession#enroll, ISession#authenticate, etc. for the given sensorId and userId.
*
* Calling this method while there is an active session is considered an error. If the
* framework is in a bad state and for some reason cannot close its session, it should use
* the reset method below.
* Calling this method while there is an active session is considered an error. If the framework
* wants to create a new session when it already has an active session, it must first cancel the
* current operation if it's cancellable or wait until it completes. Then, the framework must
* explicitly close the session with ISession#close. Once the framework receives
* ISessionCallback#onSessionClosed, a new session can be created.
*
* Implementations must store user-specific state or metadata in /data/vendor_de/<user>/facedata
* as specified by the SELinux policy. The directory /data/vendor_de is managed by vold (see
* vold_prepare_subdirs.cpp). Implementations may store additional user-specific data, such as
* embeddings or templates in StrongBox.
* embeddings or templates, in StrongBox.
*
* @param sensorId The sensorId with which this session is being created.
* @param userId The userId with which this session is being created.
* @param cb A callback to notify the framework about the session's results and events.
* @param sensorId The sensorId for which this session is being created.
* @param userId The userId for which this session is being created.
* @param cb A callback to notify the framework about the session's events.
* @return A new session.
*/
ISession createSession(in int sensorId, in int userId, in ISessionCallback cb);

View File

@@ -24,13 +24,12 @@ import android.hardware.common.NativeHandle;
import android.hardware.keymaster.HardwareAuthToken;
/**
* Operations that can be performed for unique sessions retrieved via IFace#createSession.
* Operations defined within this interface can be divided into the following categories:
* 1) Cancellable operations. These are usually the operations that can execute for several
* minutes. To allow for cancellation, they return an instance of ICancellationSignal that
* lets the framework cancel them by calling ICancellationSignal#cancel. If such an operation
* is cancelled, it must notify the framework by calling ISessionCallback#onError with
* Error::CANCELED.
* minutes. To allow for cancellation, they return an instance of ICancellationSignal that
* lets the framework cancel them by calling ICancellationSignal#cancel. If such an operation
* is cancelled, it must notify the framework by calling ISessionCallback#onError with
* Error::CANCELED.
* 2) Non-cancellable operations. Such operations cannot be cancelled once started.
*
* The lifecycle of an operation ends when one of its terminal callbacks is called. For example,
@@ -83,15 +82,20 @@ interface ISession {
* | 0 | 10 | <Time4> | <Random4> |
* ----------------------------------------------
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onChallengeGenerated
*
*/
void generateChallenge();
/**
* revokeChallenge:
*
* Revokes a challenge that was previously generated. Note that if an invalid combination of
* parameters is requested, the implementation must still notify the framework using the
* provided callback.
* Revokes a challenge that was previously generated. Note that if a non-existent challenge is
* provided, the HAL must still notify the framework using ISessionCallback#onChallengeRevoked.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onChallengeRevoked
*
* @param challenge Challenge that should be revoked.
*/
@@ -100,9 +104,9 @@ interface ISession {
/**
* getEnrollmentConfig:
*
* Returns the enrollment configuration depending on the provided enrollment type. Enrollment
* configuration determines how many stages the enrollment will have and the requirements for
* each of the stages.
* Returns the enrollment configuration for the provided enrollment type. Enrollment
* configuration determines how many stages the enrollment will have and the requirements
* for each of the stages.
*
* @param enrollmentType See the EnrollmentType enum.
* @return An EnrollmentStageConfig array that describes each enrollment stage.
@@ -117,22 +121,28 @@ interface ISession {
* At any point during enrollment, if a non-recoverable error occurs, the HAL must notify the
* framework via ISessionCallback#onError with the applicable enrollment-specific error.
*
* Before capturing face data, the implementation must first verify the authenticity and
* integrity of the provided HardwareAuthToken. In addition, it must check that the challenge
* within the provided HardwareAuthToken is valid. See ISession#generateChallenge. If any of
* the above checks fail, the framework must be notified using ISessionCallback#onError with
* Error::UNABLE_TO_PROCESS.
* Before capturing face data, the HAL must first verify the authenticity and integrity of the
* provided HardwareAuthToken. In addition, it must check that the challenge within the provided
* HardwareAuthToken is valid. See ISession#generateChallenge. If any of the above checks fail,
* the framework must be notified using ISessionCallback#onError with Error::UNABLE_TO_PROCESS.
*
* During enrollment, the implementation may notify the framework via
* ISessionCallback#onAcquired with messages that may be used to guide the user. This callback
* can be invoked multiple times if necessary. Similarly, the framework may be notified of
* enrollment progress changes via ISessionCallback#onEnrollmentProgress. Once the framework is
* notified that there are 0 "remaining" steps, the framework may cache the "enrollmentId". See
* During enrollment, the HAL may notify the framework via ISessionCallback#onAcquired with
* messages that may be used to guide the user. This callback can be invoked multiple times if
* necessary. Similarly, the framework may be notified of enrollment progress changes via
* ISessionCallback#onEnrollmentProgress. Once the framework is notified that there are 0
* "remaining" steps, the framework may cache the "enrollmentId". See
* ISessionCallback#onEnrollmentProgress for more info.
*
* When a face is successfully added and before the framework is notified of remaining=0, the
* implementation MUST update and associate this (sensorId, userId) pair with a new
* entropy-encoded random identifier. See ISession#getAuthenticatorId for more information.
* HAL must update and associate this (sensorId, userId) pair with a new entropy-encoded random
* identifier. See ISession#getAuthenticatorId for more information.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onError
* - ISessionCallback#onEnrollmentProgress(enrollmentId, remaining=0)
*
* Other applicable callbacks:
* - ISessionCallback#onAcquired
*
* @param hat See above documentation.
* @param enrollmentType See the EnrollmentType enum.
@@ -144,7 +154,7 @@ interface ISession {
* operation.
*/
ICancellationSignal enroll(in HardwareAuthToken hat, in EnrollmentType type,
in Feature[] features, in NativeHandle previewSurface);
in Feature[] features, in @nullable NativeHandle previewSurface);
/**
* authenticate:
@@ -154,15 +164,18 @@ interface ISession {
* At any point during authentication, if a non-recoverable error occurs, the HAL must notify
* the framework via ISessionCallback#onError with the applicable authentication-specific error.
*
* During authentication, the implementation may notify the framework via
* ISessionCallback#onAcquired with messages that may be used to guide the user. This callback
* can be invoked multiple times if necessary.
* During authentication, the HAL may notify the framework via ISessionCallback#onAcquired with
* messages that may be used to guide the user. This callback can be invoked multiple times if
* necessary.
*
* The HAL must notify the framework of accepts/rejects via ISessionCallback#onAuthentication*.
* The HAL must notify the framework of accepts/rejects via
* ISessionCallback#onAuthenticationSucceeded and ISessionCallback#onAuthenticationFailed,
* correspondingly.
*
* The authentication lifecycle ends when either
* 1) A face is accepted, and ISessionCallback#onAuthenticationSucceeded is invoked, or
* 2) Any non-recoverable error occurs (such as lockout). See the full list of
* The authentication lifecycle ends when any of the following happens:
* 1) A face is accepted, and ISessionCallback#onAuthenticationSucceeded is invoked.
* 2) A face is rejected, and ISessionCallback#onAuthenticationFailed is invoked.
* 3) Any non-recoverable error occurs (such as lockout). See the full list of
* authentication-specific errors in the Error enum.
*
* Note that upon successful authentication, the lockout counter for this (sensorId, userId)
@@ -174,16 +187,26 @@ interface ISession {
* must be set with the operationId passed in during #authenticate. If the sensor is NOT
* SensorStrength::STRONG, the HardwareAuthToken MUST be null.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onError
* - ISessionCallback#onAuthenticationSucceeded
* - ISessionCallback#onAuthenticationFailed
*
* Other applicable callbacks:
* - ISessionCallback#onAcquired
* - ISessionCallback#onLockoutTimed
* - ISessionCallback#onLockoutPermanent
*
* @param operationId For sensors configured as SensorStrength::STRONG, this must be used ONLY
* upon successful authentication and wrapped in the HardwareAuthToken's
* "challenge" field and sent to the framework via
* ISessionCallback#onAuthenticated. The operationId is an opaque identifier
* created from a separate secure subsystem such as, but not limited to
* KeyStore/KeyMaster. The HardwareAuthToken can then be used as an
* attestation for the provided operation. For example, this is used
* to unlock biometric-bound auth-per-use keys (see
* ISessionCallback#onAuthenticationSucceeded. The operationId is an opaque
* identifier created from a separate secure subsystem such as, but not
* limited to KeyStore/KeyMaster. The HardwareAuthToken can then be used as
* an attestation for the provided operation. For example, this is used to
* unlock biometric-bound auth-per-use keys (see
* setUserAuthenticationParameters in KeyGenParameterSpec.Builder and
* KeyProtection.Builder.
* KeyProtection.Builder).
* @return ICancellationSignal An object that can be used by the framework to cancel this
* operation.
*/
@@ -193,32 +216,36 @@ interface ISession {
* detectInteraction:
*
* A request to start looking for faces without performing matching. Must only be called if
* SensorProps#supportsDetectInteraction is true. If invoked on implementations that do not
* support this functionality, the HAL must respond with ISession#onError(UNABLE_TO_PROCESS, 0).
* SensorProps#supportsDetectInteraction is true. If invoked on HALs that do not support this
* functionality, the HAL must respond with ISession#onError(UNABLE_TO_PROCESS, 0).
*
* The framework will use this method in cases where determing user presence is required, but
* identifying/authentication is not. For example, when the device is encrypted (first boot) or
* in lockdown mode.
* The framework will use this operation in cases where determining user presence is required,
* but identifying/authenticating is not. For example, when the device is encrypted (first boot)
* or in lockdown mode.
*
* At any point during detectInteraction, if a non-recoverable error occurs, the HAL must notify
* the framework via ISessionCallback#onError with the applicable error.
*
* The implementation must only check for a face-like image was detected (e.g. to
* minimize interactions due to non-face objects), and the lockout counter must not
* be modified.
* The HAL must only check whether a face-like image was detected (e.g. to minimize interactions
* due to non-face objects), and the lockout counter must not be modified.
*
* Upon detecting any face, the implementation must invoke
* ISessionCallback#onInteractionDetected.
* Upon detecting any face, the HAL must invoke ISessionCallback#onInteractionDetected.
*
* The lifecycle of this operation ends when either
* The lifecycle of this operation ends when either:
* 1) Any face is detected and the framework is notified via
* ISessionCallback#onInteractiondetected
* 2) The operation was cancelled by the framework (see ICancellationSignal)
* 3) An error occurred, for example ERROR::TIMEOUT
* ISessionCallback#onInteractionDetected.
* 2) An error occurrs, for example Error::TIMEOUT.
*
* Note that if the operation is canceled, the implementation must notify the framework via
* Note that if the operation is canceled, the HAL must notify the framework via
* ISessionCallback#onError with Error::CANCELED.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onError
* - ISessionCallback#onInteractionDetected
*
* Other applicable callbacks:
* - ISessionCallback#onAcquired
*
* @return ICancellationSignal An object that can be used by the framework to cancel this
* operation.
*/
@@ -227,12 +254,14 @@ interface ISession {
/*
* enumerateEnrollments:
*
* A request to enumerate (list) the enrollments for this (sensorId, userId) pair. The
* framework typically uses this to ensure that its cache is in sync with the HAL.
* A request to enumerate (list) the enrollments for this (sensorId, userId) pair. The framework
* typically uses this to ensure that its cache is in sync with the HAL.
*
* The implementation must then notify the framework with a list of enrollments applicable
* for the current session via ISessionCallback#onEnrollmentsEnumerated.
* The HAL must then notify the framework with a list of enrollments applicable for the current
* session via ISessionCallback#onEnrollmentsEnumerated.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onEnrollmentsEnumerated
*/
void enumerateEnrollments();
@@ -242,8 +271,12 @@ interface ISession {
* A request to remove the enrollments for this (sensorId, userId) pair.
*
* After removing the enrollmentIds from everywhere necessary (filesystem, secure subsystems,
* etc), the implementation must notify the framework via ISessionCallback#onEnrollmentsRemoved.
* etc), the HAL must notify the framework via ISessionCallback#onEnrollmentsRemoved.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onEnrollmentsRemoved
*
* @param enrollmentIds a list of enrollments that should be removed.
*/
void removeEnrollments(in int[] enrollmentIds);
@@ -257,6 +290,10 @@ interface ISession {
*
* The HAL must notify the framework about the result by calling
* ISessionCallback#onFeaturesRetrieved.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onError
* - ISessionCallback#onFeaturesRetrieved
*/
void getFeatures();
@@ -264,15 +301,19 @@ interface ISession {
* setFeature:
*
* Enables or disables a feature for this (sensorId, userId) pair. Because certain features may
* decrease security, the user must enter their password before this method is invoked
* (see @param hat). The HAL must verify the hat before changing any feature state.
* decrease security, the user must enter their password before this operation is invoked
* (see @param hat). The HAL must verify the HAT before changing any feature state.
*
* If the hat is invalid or if the user is not enrolled, the HAL must invoke
* If the HAT is invalid or if the user is not enrolled, the HAL must invoke
* ISessionCallback#onError with Error::UNABLE_TO_PROCESS.
*
* After the feature is successfully set, the HAL must notify the framework by calling
* ISessionCallback#onFeatureSet.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onError
* - ISessionCallback#onFeatureSet
*
* @param hat HardwareAuthToken See above documentation.
* @param feature The feature to be enabled or disabled.
* @param enabled Whether the provided features should be enabled or disabled.
@@ -295,8 +336,8 @@ interface ISession {
* KeyProtection.Builder.setInvalidatedByBiometricEnrollment.
*
* In addition, upon successful face authentication, the signed HAT that is returned to
* the framework via ISessionCallback#onAuthenticated must contain this identifier in the
* authenticatorId field.
* the framework via ISessionCallback#onAuthenticationSucceeded must contain this identifier in
* the authenticatorId field.
*
* Returns an entropy-encoded random identifier associated with the current set of enrollments
* via ISessionCallback#onAuthenticatorIdRetrieved. The authenticatorId
@@ -305,20 +346,21 @@ interface ISession {
* 3) MUST not change if a face is deleted.
* 4) MUST be an entropy-encoded random number
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onAuthenticatorIdRetrieved
*/
void getAuthenticatorId();
/**
* invalidateAuthenticatorId:
*
* This method only applies to sensors that are configured as SensorStrength::STRONG. If invoked
* by the framework for sensor of other strengths, the HAL should immediately invoke
* This operation only applies to sensors that are configured as SensorStrength::STRONG. If
* invoked by the framework for sensors of other strengths, the HAL should immediately invoke
* ISessionCallback#onAuthenticatorIdInvalidated.
*
* The following only applies to sensors that are configured as SensorStrength::STRONG.
*
* When invoked by the framework, the implementation must perform the following sequence of
* events:
* When invoked by the framework, the HAL must perform the following sequence of events:
* 1) Update the authenticatorId with a new entropy-encoded random number
* 2) Persist the new authenticatorId to non-ephemeral storage
* 3) Notify the framework that the above is completed, via
@@ -326,18 +368,20 @@ interface ISession {
*
* A practical use case of invalidation would be when the user adds a new enrollment to a sensor
* managed by a different HAL instance. The public android.security.keystore APIs bind keys to
* "all biometrics" rather than "face-only" or "face-only" (see #getAuthenticatorId
* for more details). As such, the framework would coordinate invalidation across multiple
* biometric HALs as necessary.
* "all biometrics" rather than "fingerprint-only" or "face-only" (see #getAuthenticatorId for
* more details). As such, the framework would coordinate invalidation across multiple biometric
* HALs as necessary.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onAuthenticatorIdInvalidated
*/
void invalidateAuthenticatorId();
/**
* resetLockout:
*
* Requests the implementation to clear the lockout counter. Upon receiving this request, the
* implementation must perform the following:
* Requests the HAL to clear the lockout counter. Upon receiving this request, the HAL must
* perform the following:
* 1) Verify the authenticity and integrity of the provided HAT
* 2) Verify that the timestamp provided within the HAT is relatively recent (e.g. on the
* order of minutes, not hours).
@@ -373,6 +417,9 @@ interface ISession {
* See the Android CDD section 7.3.10 for the full set of lockout and rate-limiting
* requirements.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onLockoutCleared
*
* @param hat HardwareAuthToken See above documentation.
*/
void resetLockout(in HardwareAuthToken hat);
@@ -384,9 +431,14 @@ interface ISession {
* If the HAL is busy performing a cancellable operation, the operation must be explicitly
* cancelled with a call to ICancellationSignal#cancel before the session can be closed.
*
* After a session is closed, the HAL must notify the framework by calling
* ISessionCallback#onSessionClosed.
*
* All sessions must be explicitly closed. Calling IFace#createSession while there is an active
* session is considered an error.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onSessionClosed
*/
void close();
}

View File

@@ -37,11 +37,11 @@ interface ISessionCallback {
/**
* This method must only be used to notify the framework during the following operations:
* 1) ISession#authenticate
* 2) ISession#detectInteraction
* - ISession#authenticate
* - ISession#detectInteraction
*
* These messages may be used to provide user guidance multiple times if necessary per
* operation.
* These messages may be used to provide user guidance multiple times per operation if
* necessary.
*
* @param frame See the AuthenticationFrame enum.
*/
@@ -51,8 +51,8 @@ interface ISessionCallback {
* This method must only be used to notify the framework during the ISession#enroll
* operation.
*
* These messages may be used to provide user guidance multiple times if necessary per
* operation.
* These messages may be used to provide user guidance multiple times per operation if
* necessary.
*
* @param frame See the EnrollmentFrame enum.
*/
@@ -60,18 +60,18 @@ interface ISessionCallback {
/**
* This method must only be used to notify the framework during the following operations:
* 1) ISession#enroll
* 2) ISession#authenticate
* 3) ISession#detectInteraction
* 4) ISession#invalidateAuthenticatorId
* 5) ISession#resetLockout
* - ISession#enroll
* - ISession#authenticate
* - ISession#detectInteraction
* - ISession#invalidateAuthenticatorId
* - ISession#resetLockout
*
* These messages may be used to notify the framework or user that a non-recoverable error
* has occurred. The operation is finished, and the HAL must proceed with the next operation
* or return to the idling state.
*
* Note that cancellation (see common::ICancellationSignal) and preemption must be followed with
* an Error::CANCELED message.
* Note that cancellation (see common::ICancellationSignal) must be followed with an
* Error::CANCELED message.
*
* @param error See the Error enum.
* @param vendorCode Only valid if error == Error::VENDOR. The vendorCode must be used to index

View File

@@ -34,12 +34,15 @@ class CancellationSignal : public common::BnCancellationSignal {
}
};
Session::Session(std::shared_ptr<ISessionCallback> cb) : cb_(std::move(cb)) {}
Session::Session(std::shared_ptr<ISessionCallback> cb)
: cb_(std::move(cb)), mRandom(std::mt19937::default_seed) {}
ndk::ScopedAStatus Session::generateChallenge() {
LOG(INFO) << "generateChallenge";
if (cb_) {
cb_->onChallengeGenerated(0);
std::uniform_int_distribution<int64_t> dist;
auto challenge = dist(mRandom);
cb_->onChallengeGenerated(challenge);
}
return ndk::ScopedAStatus::ok();
}
@@ -60,9 +63,13 @@ ndk::ScopedAStatus Session::getEnrollmentConfig(EnrollmentType /*enrollmentType*
ndk::ScopedAStatus Session::enroll(
const keymaster::HardwareAuthToken& /*hat*/, EnrollmentType /*enrollmentType*/,
const std::vector<Feature>& /*features*/, const NativeHandle& /*previewSurface*/,
const std::vector<Feature>& /*features*/,
const std::optional<NativeHandle>& /*previewSurface*/,
std::shared_ptr<biometrics::common::ICancellationSignal>* /*return_val*/) {
LOG(INFO) << "enroll";
if (cb_) {
cb_->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
}
return ndk::ScopedAStatus::ok();
}
@@ -100,6 +107,10 @@ ndk::ScopedAStatus Session::removeEnrollments(const std::vector<int32_t>& /*enro
ndk::ScopedAStatus Session::getFeatures() {
LOG(INFO) << "getFeatures";
if (cb_) {
// Must error out with UNABLE_TO_PROCESS when no faces are enrolled.
cb_->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorCode */);
}
return ndk::ScopedAStatus::ok();
}
@@ -119,6 +130,9 @@ ndk::ScopedAStatus Session::getAuthenticatorId() {
ndk::ScopedAStatus Session::invalidateAuthenticatorId() {
LOG(INFO) << "invalidateAuthenticatorId";
if (cb_) {
cb_->onAuthenticatorIdInvalidated(0);
}
return ndk::ScopedAStatus::ok();
}

View File

@@ -16,6 +16,8 @@
#pragma once
#include <random>
#include <aidl/android/hardware/biometrics/face/BnSession.h>
#include <aidl/android/hardware/biometrics/face/ISessionCallback.h>
@@ -39,7 +41,7 @@ class Session : public BnSession {
ndk::ScopedAStatus enroll(const keymaster::HardwareAuthToken& hat,
EnrollmentType enrollmentType, const std::vector<Feature>& features,
const NativeHandle& previewSurface,
const std::optional<NativeHandle>& previewSurface,
std::shared_ptr<common::ICancellationSignal>* return_val) override;
ndk::ScopedAStatus authenticate(
@@ -68,6 +70,7 @@ class Session : public BnSession {
private:
std::shared_ptr<ISessionCallback> cb_;
std::mt19937 mRandom;
};
} // namespace aidl::android::hardware::biometrics::face

View File

@@ -29,16 +29,26 @@ namespace {
using namespace std::literals::chrono_literals;
using aidl::android::hardware::common::NativeHandle;
constexpr int kSensorId = 0;
constexpr int kUserId = 0;
class SessionCallback : public BnSessionCallback {
public:
ndk::ScopedAStatus onChallengeGenerated(int64_t /*challenge*/) override {
ndk::ScopedAStatus onChallengeGenerated(int64_t challenge) override {
auto lock = std::lock_guard{mMutex};
mOnChallengeGeneratedInvoked = true;
mGeneratedChallenge = challenge;
mCv.notify_one();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus onChallengeRevoked(int64_t /*challenge*/) override {
ndk::ScopedAStatus onChallengeRevoked(int64_t challenge) override {
auto lock = std::lock_guard{mMutex};
mOnChallengeRevokedInvoked = true;
mRevokedChallenge = challenge;
mCv.notify_one();
return ndk::ScopedAStatus::ok();
}
@@ -83,15 +93,24 @@ class SessionCallback : public BnSessionCallback {
ndk::ScopedAStatus onEnrollmentsEnumerated(
const std::vector<int32_t>& /*enrollmentIds*/) override {
auto lock = std::lock_guard{mMutex};
mOnEnrollmentsEnumeratedInvoked = true;
mCv.notify_one();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus onEnrollmentsRemoved(
const std::vector<int32_t>& /*enrollmentIds*/) override {
auto lock = std::lock_guard{mMutex};
mOnEnrollmentsRemovedInvoked = true;
mCv.notify_one();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus onFeaturesRetrieved(const std::vector<Feature>& /*features*/) override {
auto lock = std::lock_guard{mMutex};
mOnFeaturesRetrievedInvoked = true;
mCv.notify_one();
return ndk::ScopedAStatus::ok();
}
@@ -100,10 +119,16 @@ class SessionCallback : public BnSessionCallback {
}
ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t /*authenticatorId*/) override {
auto lock = std::lock_guard{mMutex};
mOnAuthenticatorIdRetrievedInvoked = true;
mCv.notify_one();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t /*newAuthenticatorId*/) override {
auto lock = std::lock_guard{mMutex};
mOnAuthenticatorIdInvalidatedInvoked = true;
mCv.notify_one();
return ndk::ScopedAStatus::ok();
}
@@ -118,45 +143,181 @@ class SessionCallback : public BnSessionCallback {
std::condition_variable mCv;
Error mError = Error::UNKNOWN;
int32_t mVendorCode = 0;
int64_t mGeneratedChallenge = 0;
int64_t mRevokedChallenge = 0;
bool mOnChallengeGeneratedInvoked = false;
bool mOnChallengeRevokedInvoked = false;
bool mOnErrorInvoked = false;
bool mOnEnrollmentsEnumeratedInvoked = false;
bool mOnEnrollmentsRemovedInvoked = false;
bool mOnFeaturesRetrievedInvoked = false;
bool mOnAuthenticatorIdRetrievedInvoked = false;
bool mOnAuthenticatorIdInvalidatedInvoked = false;
bool mOnSessionClosedInvoked = false;
};
class Face : public testing::TestWithParam<std::string> {
protected:
void SetUp() override {
AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
ASSERT_NE(binder, nullptr);
mHal = IFace::fromBinder(ndk::SpAIBinder(binder));
// Prepare the callback.
mCb = ndk::SharedRefBase::make<SessionCallback>();
int retries = 0;
bool isOk = false;
// If the first attempt to create a session fails, we try to create a session again. The
// first attempt might fail if the framework already has an active session. The AIDL
// contract doesn't allow to create a new session without closing the old one. However, we
// can't close the framework's session from VTS. The expectation here is that the HAL will
// crash after the first illegal attempt to create a session, then it will restart, and then
// we'll be able to create a session.
do {
// Get an instance of the HAL.
AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
ASSERT_NE(binder, nullptr);
mHal = IFace::fromBinder(ndk::SpAIBinder(binder));
// Create a session.
isOk = mHal->createSession(kSensorId, kUserId, mCb, &mSession).isOk();
++retries;
} while (!isOk && retries < 2);
ASSERT_TRUE(isOk);
}
void TearDown() override {
// Close the mSession.
ASSERT_TRUE(mSession->close().isOk());
// Make sure the mSession is closed.
auto lock = std::unique_lock<std::mutex>(mCb->mMutex);
mCb->mCv.wait(lock, [this] { return mCb->mOnSessionClosedInvoked; });
}
std::shared_ptr<IFace> mHal;
std::shared_ptr<SessionCallback> mCb;
std::shared_ptr<ISession> mSession;
};
TEST_P(Face, AuthenticateTest) {
// Prepare the callback.
auto cb = ndk::SharedRefBase::make<SessionCallback>();
TEST_P(Face, GetSensorPropsWorksTest) {
std::vector<SensorProps> sensorProps;
// Create a session
std::shared_ptr<ISession> session;
ASSERT_TRUE(mHal->createSession(kSensorId, kUserId, cb, &session).isOk());
// Call the method.
ASSERT_TRUE(mHal->getSensorProps(&sensorProps).isOk());
// Call authenticate
// Make sure the sensorProps aren't empty.
ASSERT_FALSE(sensorProps.empty());
ASSERT_FALSE(sensorProps[0].commonProps.componentInfo.empty());
}
TEST_P(Face, EnrollWithBadHatResultsInErrorTest) {
// Call the method.
auto hat = keymaster::HardwareAuthToken{};
std::shared_ptr<common::ICancellationSignal> cancellationSignal;
ASSERT_TRUE(session->authenticate(0 /* operationId */, &cancellationSignal).isOk());
ASSERT_TRUE(
mSession->enroll(hat, EnrollmentType::DEFAULT, {}, std::nullopt, &cancellationSignal)
.isOk());
auto lock = std::unique_lock<std::mutex>(cb->mMutex);
cb->mCv.wait(lock, [&cb] { return cb->mOnErrorInvoked; });
// Get the results
EXPECT_EQ(cb->mError, Error::UNABLE_TO_PROCESS);
EXPECT_EQ(cb->mVendorCode, 0);
// Make sure an error is returned.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnErrorInvoked; });
EXPECT_EQ(mCb->mError, Error::UNABLE_TO_PROCESS);
EXPECT_EQ(mCb->mVendorCode, 0);
}
TEST_P(Face, GenerateChallengeProducesUniqueChallengesTest) {
static constexpr int kIterations = 100;
auto challenges = std::set<int>{};
for (unsigned int i = 0; i < kIterations; ++i) {
// Call the method.
ASSERT_TRUE(mSession->generateChallenge().isOk());
// Check that the generated challenge is unique and not 0.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeGeneratedInvoked; });
ASSERT_NE(mCb->mGeneratedChallenge, 0);
ASSERT_EQ(challenges.find(mCb->mGeneratedChallenge), challenges.end());
challenges.insert(mCb->mGeneratedChallenge);
mCb->mOnChallengeGeneratedInvoked = false;
}
}
TEST_P(Face, RevokeChallengeWorksForNonexistentChallengeTest) {
const int64_t nonexistentChallenge = 123;
// Call the method.
ASSERT_TRUE(mSession->revokeChallenge(nonexistentChallenge).isOk());
// Check that the challenge is revoked and matches the requested challenge.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeRevokedInvoked; });
ASSERT_EQ(mCb->mRevokedChallenge, nonexistentChallenge);
}
TEST_P(Face, RevokeChallengeWorksForExistentChallengeTest) {
// Generate a challenge.
ASSERT_TRUE(mSession->generateChallenge().isOk());
// Wait for the result.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeGeneratedInvoked; });
lock.unlock();
// Close the session
ASSERT_TRUE(session->close().isOk());
// Revoke the challenge.
ASSERT_TRUE(mSession->revokeChallenge(mCb->mGeneratedChallenge).isOk());
// Check that the challenge is revoked and matches the requested challenge.
lock.lock();
cb->mCv.wait(lock, [&cb] { return cb->mOnSessionClosedInvoked; });
mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeRevokedInvoked; });
ASSERT_EQ(mCb->mRevokedChallenge, mCb->mGeneratedChallenge);
}
TEST_P(Face, EnumerateEnrollmentsWorksTest) {
// Call the method.
ASSERT_TRUE(mSession->enumerateEnrollments().isOk());
// Wait for the result.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnEnrollmentsEnumeratedInvoked; });
}
TEST_P(Face, RemoveEnrollmentsWorksTest) {
// Call the method.
ASSERT_TRUE(mSession->removeEnrollments({}).isOk());
// Wait for the result.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnEnrollmentsRemovedInvoked; });
}
TEST_P(Face, GetFeaturesWithoutEnrollmentsResultsInUnableToProcess) {
// Call the method.
ASSERT_TRUE(mSession->getFeatures().isOk());
// Wait for the result.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnErrorInvoked; });
EXPECT_EQ(mCb->mError, Error::UNABLE_TO_PROCESS);
EXPECT_EQ(mCb->mVendorCode, 0);
}
TEST_P(Face, GetAuthenticatorIdWorksTest) {
// Call the method.
ASSERT_TRUE(mSession->getAuthenticatorId().isOk());
// Wait for the result.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnAuthenticatorIdRetrievedInvoked; });
}
TEST_P(Face, InvalidateAuthenticatorIdWorksTest) {
// Call the method.
ASSERT_TRUE(mSession->invalidateAuthenticatorId().isOk());
// Wait for the result.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnAuthenticatorIdInvalidatedInvoked; });
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Face);

View File

@@ -19,6 +19,10 @@ package android.hardware.biometrics.fingerprint@2.3;
import @2.2::IBiometricsFingerprint;
/**
* New use of this interface is strongly discouraged. The recommended option is
* to use the AIDL interface, android.hardware.biometrics.fingerprint
* (IFingerprint).
*
* The interface for biometric fingerprint authentication.
*/
interface IBiometricsFingerprint extends @2.2::IBiometricsFingerprint {

View File

@@ -25,31 +25,31 @@ interface IFingerprint {
/**
* getSensorProps:
*
* @return A list of properties for all sensors that an instance of the HAL supports.
* @return A list of properties for all of the fingerprint sensors supported by the HAL.
*/
SensorProps[] getSensorProps();
/**
* createSession:
*
* Creates a instance of ISession which can be used by the framework to perform operations
* such as ISession#enroll, ISession#authenticate, etc. for the given sensorId and userId.
* Creates an instance of ISession that can be used by the framework to perform operations such
* as ISession#enroll, ISession#authenticate, etc. for the given sensorId and userId.
*
* Calling this method while there is an active session is considered an error. If the framework
* wants to create a new session when it already has an active session, it must first cancel the
* current operation if it's cancellable, or wait until it completes. Then, the framework must
* current operation if it's cancellable or wait until it completes. Then, the framework must
* explicitly close the session with ISession#close. Once the framework receives
* ISessionCallback#onSessionClosed, a new session can be created.
*
* Implementations must store user-specific state or metadata in /data/vendor_de/<user>/fpdata
* as specified by the SeLinux policy. This directory is created/removed by vold (see
* as specified by the SELinux policy. The directory /data/vendor_de is managed by vold (see
* vold_prepare_subdirs.cpp). Implementations may store additional user-specific data, such as
* embeddings or templates in StrongBox.
* embeddings or templates, in StrongBox.
*
* @param sensorId The sensor with which this session is being created.
* @param userId The userId with which this session is being created.
* @param cb Used to notify the framework.
* @return A new session
* @param sensorId The sensorId for which this session is being created.
* @param userId The userId for which this session is being created.
* @param cb A callback to notify the framework about the session's events.
* @return A new session.
*/
ISession createSession(in int sensorId, in int userId, in ISessionCallback cb);
}

View File

@@ -20,30 +20,29 @@ import android.hardware.biometrics.common.ICancellationSignal;
import android.hardware.keymaster.HardwareAuthToken;
/**
* Operations that can be performed for unique sessions retrieved via IFingerprint#createSession.
* Methods defined within this interface can be split into the following categories:
* 1) Non-interrupting operations. These operations are handled by the HAL in FIFO order.
* 1a) Cancellable operations. These are usually the operations that can execute for several
* minutes. To allow for cancellation, they return an instance of ICancellationSignal that
* lets the framework cancel them by calling ICancellationSignal#cancel. If such an operation
* is cancelled, it must notify the framework by calling ISessionCallback#onError with
* Error::CANCELED.
* 1b) Non-cancellable operations. Such operations cannot be cancelled once started.
* Operations defined within this interface can be split into the following categories:
* 1) Non-interrupting operations. These operations are handled by the HAL in a FIFO order.
* 1a) Cancellable operations. These operations can usually run for several minutes. To allow
* for cancellation, they return an instance of ICancellationSignal that allows the
* framework to cancel them by calling ICancellationSignal#cancel. If such an operation is
* cancelled, it must notify the framework by calling ISessionCallback#onError with
* Error::CANCELED.
* 1b) Non-cancellable operations. Such operations cannot be cancelled once started.
* 2) Interrupting operations. These operations may be invoked by the framework immediately,
* regardless of whether another operation is executing. For example, on devices with sensors
* of FingerprintSensorType::UNDER_DISPLAY_*, ISession#onFingerDown may be invoked while the
* of FingerprintSensorType::UNDER_DISPLAY_*, ISession#onPointerDown may be invoked while the
* HAL is executing ISession#enroll, ISession#authenticate or ISession#detectInteraction.
*
* The lifecycle of a non-interrupting operation ends when one of its terminal callbacks is called.
* For example, ISession#authenticate is considered completed when either of the following callbacks
* is called: ISessionCallback#onError or ISessionCallback#onAuthenticationSucceeded.
* The lifecycle of a non-interrupting operation ends when one of its final callbacks is called.
* For example, ISession#authenticate is considered completed when either ISessionCallback#onError
* or ISessionCallback#onAuthenticationSucceeded is called.
*
* The lifecycle of an interrupting operation ends when it returns. Interrupting operations do not
* have callbacks.
*
* ISession only supports execution of one non-interrupting operation at a time, regardless of
* whether it's cancellable. The framework must wait for a corresponding callback indicating the end
* of the current non-interrupting operation before a new non-interrupting operation can be started.
* whether it's cancellable. The framework must wait for a callback indicating the end of the
* current non-interrupting operation before a new non-interrupting operation can be started.
*/
@VintfStability
interface ISession {
@@ -89,15 +88,19 @@ interface ISession {
* | 0 | 10 | <Time4> | <Random4> |
* ----------------------------------------------
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onChallengeGenerated
*/
void generateChallenge();
/**
* revokeChallenge:
*
* Revokes a challenge that was previously generated. Note that if an invalid combination of
* parameters is requested, the implementation must still notify the framework using the
* provided callback.
* Revokes a challenge that was previously generated. Note that if a non-existent challenge is
* provided, the HAL must still notify the framework using ISessionCallback#onChallengeRevoked.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onChallengeRevoked
*
* @param challenge Challenge that should be revoked.
*/
@@ -111,26 +114,33 @@ interface ISession {
* At any point during enrollment, if a non-recoverable error occurs, the HAL must notify the
* framework via ISessionCallback#onError with the applicable enrollment-specific error.
*
* Before capturing fingerprint data, the implementation must first verify the authenticity and
* integrity of the provided HardwareAuthToken. In addition, it must check that the challenge
* within the provided HardwareAuthToken is valid. See ISession#generateChallenge. If any of
* the above checks fail, the framework must be notified via ISessionCallback#onError and the
* HAL must notify the framework when it returns to the idle state. See
* Before capturing fingerprint data, the HAL must first verify the authenticity and integrity
* of the provided HardwareAuthToken. In addition, it must check that the challenge within the
* provided HardwareAuthToken is valid. See ISession#generateChallenge. If any of the above
* checks fail, the framework must be notified using ISessionCallback#onError with
* Error::UNABLE_TO_PROCESS.
*
* During enrollment, the implementation may notify the framework via
* ISessionCallback#onAcquired with messages that may be used to guide the user. This callback
* can be invoked multiple times if necessary. Similarly, the framework may be notified of
* enrollment progress changes via ISessionCallback#onEnrollmentProgress. Once the framework is
* notified that there are 0 "remaining" steps, the framework may cache the "enrollmentId". See
* ISessionCallback#onEnrollmentProgress for more info. The HAL must notify the framework once
* it returns to the idle state.
* During enrollment, the HAL may notify the framework via ISessionCallback#onAcquired with
* messages that may be used to guide the user. This callback can be invoked multiple times if
* necessary. Similarly, the framework may be notified of enrollment progress changes via
* ISessionCallback#onEnrollmentProgress. Once the framework is notified that there are 0
* "remaining" steps, the framework may cache the "enrollmentId". See
* ISessionCallback#onEnrollmentProgress for more info.
*
* When a finger is successfully added and before the framework is notified of remaining=0, the
* implementation MUST update and associate this (sensorId, userId) pair with a new new
* entropy-encoded random identifier. See ISession#getAuthenticatorId for more information.
* HAL must update and associate this (sensorId, userId) pair with a new entropy-encoded random
* identifier. See ISession#getAuthenticatorId for more information.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onError
* - ISessionCallback#onEnrollmentProgress(enrollmentId, remaining=0)
*
* Other applicable callbacks:
* - ISessionCallback#onAcquired
*
* @param hat See above documentation.
* @return ICancellationSignal An object that can be used by the framework to cancel this
* operation.
*/
ICancellationSignal enroll(in HardwareAuthToken hat);
@@ -142,14 +152,16 @@ interface ISession {
* At any point during authentication, if a non-recoverable error occurs, the HAL must notify
* the framework via ISessionCallback#onError with the applicable authentication-specific error.
*
* During authentication, the implementation may notify the framework via
* ISessionCallback#onAcquired with messages that may be used to guide the user. This callback
* can be invoked multiple times if necessary.
* During authentication, the HAL may notify the framework via ISessionCallback#onAcquired with
* messages that may be used to guide the user. This callback can be invoked multiple times if
* necessary.
*
* The HAL must notify the framework of accepts/rejects via ISessionCallback#onAuthentication*.
* The HAL must notify the framework of accepts and rejects via
* ISessionCallback#onAuthenticationSucceeded and ISessionCallback#onAuthenticationFailed,
* correspondingly.
*
* The authentication lifecycle ends when either
* 1) A fingerprint is accepted, and ISessionCallback#onAuthenticationSucceeded is invoked, or
* The authentication lifecycle ends when either:
* 1) A fingerprint is accepted, and ISessionCallback#onAuthenticationSucceeded is invoked.
* 2) Any non-recoverable error occurs (such as lockout). See the full list of
* authentication-specific errors in the Error enum.
*
@@ -162,16 +174,28 @@ interface ISession {
* must be set with the operationId passed in during #authenticate. If the sensor is NOT
* SensorStrength::STRONG, the HardwareAuthToken MUST be null.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onError
* - ISessionCallback#onAuthenticationSucceeded
*
* Other applicable callbacks:
* - ISessionCallback#onAcquired
* - ISessionCallback#onAuthenticationFailed
* - ISessionCallback#onLockoutTimed
* - ISessionCallback#onLockoutPermanent
*
* @param operationId For sensors configured as SensorStrength::STRONG, this must be used ONLY
* upon successful authentication and wrapped in the HardwareAuthToken's
* "challenge" field and sent to the framework via
* ISessionCallback#onAuthenticated. The operationId is an opaque identifier
* created from a separate secure subsystem such as, but not limited to
* KeyStore/KeyMaster. The HardwareAuthToken can then be used as an
* attestation for the provided operation. For example, this is used
* to unlock biometric-bound auth-per-use keys (see
* ISessionCallback#onAuthenticationSucceeded. The operationId is an opaque
* identifier created from a separate secure subsystem such as, but not
* limited to KeyStore/KeyMaster. The HardwareAuthToken can then be used as
* an attestation for the provided operation. For example, this is used to
* unlock biometric-bound auth-per-use keys (see
* setUserAuthenticationParameters in KeyGenParameterSpec.Builder and
* KeyProtection.Builder.
* KeyProtection.Builder).
* @return ICancellationSignal An object that can be used by the framework to cancel this
* operation.
*/
ICancellationSignal authenticate(in long operationId);
@@ -179,44 +203,52 @@ interface ISession {
* detectInteraction:
*
* A request to start looking for fingerprints without performing matching. Must only be called
* if SensorProps#supportsDetectInteraction is true. If invoked on implementations that do not
* support this functionality, the HAL must respond with ISession#onError(UNABLE_TO_PROCESS, 0).
* if SensorProps#supportsDetectInteraction is true. If invoked on HALs that do not support this
* functionality, the HAL must respond with ISession#onError(UNABLE_TO_PROCESS, 0).
*
* The framework will use this method in cases where determing user presence is required, but
* identifying/authentication is not. For example, when the device is encrypted (first boot) or
* in lockdown mode.
* The framework will use this operation in cases where determining user presence is required,
* but identifying/authenticating is not. For example, when the device is encrypted (first boot)
* or in lockdown mode.
*
* At any point during detectInteraction, if a non-recoverable error occurs, the HAL must notify
* the framework via ISessionCallback#onError with the applicable error.
*
* The implementation must only check for a fingerprint-like image was detected (e.g. to
* minimize interactions due to non-fingerprint objects), and the lockout counter must not
* be modified.
* The HAL must only check whether a fingerprint-like image was detected (e.g. to minimize
* interactions due to non-fingerprint objects), and the lockout counter must not be modified.
*
* Upon detecting any fingerprint, the implementation must invoke
* ISessionCallback#onInteractionDetected.
* Upon detecting any fingerprint, the HAL must invoke ISessionCallback#onInteractionDetected.
*
* The lifecycle of this operation ends when either
* The lifecycle of this operation ends when either:
* 1) Any fingerprint is detected and the framework is notified via
* ISessionCallback#onInteractiondetected
* 2) The operation was cancelled by the framework (see ICancellationSignal)
* 3) The HAL ends the operation, for example when a subsequent operation pre-empts this one.
* ISessionCallback#onInteractionDetected.
* 2) An error occurs, for example Error::TIMEOUT.
*
* Note that if the operation is canceled, the implementation must notify the framework via
* Note that if the operation is canceled, the HAL must notify the framework via
* ISessionCallback#onError with Error::CANCELED.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onError
* - ISessionCallback#onInteractionDetected
*
* Other applicable callbacks:
* - ISessionCallback#onAcquired
*
* @return ICancellationSignal An object that can be used by the framework to cancel this
* operation.
*/
ICancellationSignal detectInteraction();
/*
* enumerateEnrollments:
*
* A request to enumerate (list) the enrollments for this (sensorId, userId) pair. The
* framework typically uses this to ensure that its cache is in sync with the HAL.
* A request to enumerate (list) the enrollments for this (sensorId, userId) pair. The framework
* typically uses this to ensure that its cache is in sync with the HAL.
*
* The implementation must then notify the framework with a list of enrollments applicable
* for the current session via ISessionCallback#onEnrollmentsEnumerated.
* The HAL must then notify the framework with a list of enrollments applicable for the current
* session via ISessionCallback#onEnrollmentsEnumerated.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onEnrollmentsEnumerated
*/
void enumerateEnrollments();
@@ -226,8 +258,12 @@ interface ISession {
* A request to remove the enrollments for this (sensorId, userId) pair.
*
* After removing the enrollmentIds from everywhere necessary (filesystem, secure subsystems,
* etc), the implementation must notify the framework via ISessionCallback#onEnrollmentsRemoved.
* etc), the HAL must notify the framework via ISessionCallback#onEnrollmentsRemoved.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onEnrollmentsRemoved
*
* @param enrollmentIds a list of enrollments that should be removed.
*/
void removeEnrollments(in int[] enrollmentIds);
@@ -240,15 +276,15 @@ interface ISession {
* The following only applies to sensors that are configured as SensorStrength::STRONG.
*
* The authenticatorId is a (sensorId, user)-specific identifier which can be used during key
* generation and key import to to associate a key (in KeyStore / KeyMaster) with the current
* set of enrolled fingerprints. For example, the following public Android APIs allow for keys
* to be invalidated when the user adds a new enrollment after the key was created:
* generation and import to associate the key (in KeyStore / KeyMaster) with the current set of
* enrolled fingerprints. For example, the following public Android APIs allow for keys to be
* invalidated when the user adds a new enrollment after the key was created:
* KeyGenParameterSpec.Builder.setInvalidatedByBiometricEnrollment and
* KeyProtection.Builder.setInvalidatedByBiometricEnrollment.
*
* In addition, upon successful fingerprint authentication, the signed HAT that is returned to
* the framework via ISessionCallback#onAuthenticated must contain this identifier in the
* authenticatorId field.
* the framework via ISessionCallback#onAuthenticationSucceeded must contain this identifier in
* the authenticatorId field.
*
* Returns an entropy-encoded random identifier associated with the current set of enrollments
* via ISessionCallback#onAuthenticatorIdRetrieved. The authenticatorId
@@ -257,20 +293,21 @@ interface ISession {
* 3) MUST not change if a fingerprint is deleted.
* 4) MUST be an entropy-encoded random number
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onAuthenticatorIdRetrieved
*/
void getAuthenticatorId();
/**
* invalidateAuthenticatorId:
*
* This method only applies to sensors that are configured as SensorStrength::STRONG. If invoked
* by the framework for sensor of other strengths, the HAL should immediately invoke
* This operation only applies to sensors that are configured as SensorStrength::STRONG. If
* invoked by the framework for sensors of other strengths, the HAL should immediately invoke
* ISessionCallback#onAuthenticatorIdInvalidated.
*
* The following only applies to sensors that are configured as SensorStrength::STRONG.
*
* When invoked by the framework, the implementation must perform the following sequence of
* events:
* When invoked by the framework, the HAL must perform the following sequence of events:
* 1) Update the authenticatorId with a new entropy-encoded random number
* 2) Persist the new authenticatorId to non-ephemeral storage
* 3) Notify the framework that the above is completed, via
@@ -278,23 +315,25 @@ interface ISession {
*
* A practical use case of invalidation would be when the user adds a new enrollment to a sensor
* managed by a different HAL instance. The public android.security.keystore APIs bind keys to
* "all biometrics" rather than "fingerprint-only" or "face-only" (see #getAuthenticatorId
* for more details). As such, the framework would coordinate invalidation across multiple
* biometric HALs as necessary.
* "all biometrics" rather than "fingerprint-only" or "face-only" (see #getAuthenticatorId for
* more details). As such, the framework would coordinate invalidation across multiple biometric
* HALs as necessary.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onAuthenticatorIdInvalidated
*/
void invalidateAuthenticatorId();
/**
* resetLockout:
*
* Requests the implementation to clear the lockout counter. Upon receiving this request, the
* implementation must perform the following:
* Requests the HAL to clear the lockout counter. Upon receiving this request, the HAL must
* perform the following:
* 1) Verify the authenticity and integrity of the provided HAT
* 2) Verify that the timestamp provided within the HAT is relatively recent (e.g. on the
* order of minutes, not hours).
* If either of the checks fail, the HAL must invoke ISessionCallback#onError with
* Error::UNABLE_TO_PROCESS and return to the idling state.
* Error::UNABLE_TO_PROCESS.
*
* Upon successful verification, the HAL must clear the lockout counter and notify the framework
* via ISessionCallback#onLockoutCleared.
@@ -325,6 +364,9 @@ interface ISession {
* See the Android CDD section 7.3.10 for the full set of lockout and rate-limiting
* requirements.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onLockoutCleared
*
* @param hat HardwareAuthToken See above documentation.
*/
void resetLockout(in HardwareAuthToken hat);
@@ -343,6 +385,8 @@ interface ISession {
* All sessions must be explicitly closed. Calling IFingerprint#createSession while there is an
* active session is considered an error.
*
* Callbacks that signify the end of this operation's lifecycle:
* - ISessionCallback#onSessionClosed
*/
void close();
@@ -353,16 +397,16 @@ interface ISession {
/**
* onPointerDown:
*
* This method only applies to sensors that are configured as
* This operation only applies to sensors that are configured as
* FingerprintSensorType::UNDER_DISPLAY_*. If invoked erroneously by the framework for sensors
* of other types, the HAL must treat this as a no-op and return immediately.
*
* For sensors of type FingerprintSensorType::UNDER_DISPLAY_*, this method is used to notify the
* HAL of display touches. This method can be invoked when the HAL is performing any one of:
* ISession#authenticate, ISession#enroll, ISession#detectInteraction.
* This operation is used to notify the HAL of display touches. This operation can be invoked
* when the HAL is performing any one of: ISession#authenticate, ISession#enroll,
* ISession#detectInteraction.
*
* Note that the framework will only invoke this method if the event occurred on the display on
* which this sensor is located.
* Note that the framework will only invoke this operation if the event occurred on the display
* on which this sensor is located.
*
* Note that for sensors which require illumination such as
* FingerprintSensorType::UNDER_DISPLAY_OPTICAL, and where illumination is handled below the
@@ -379,10 +423,13 @@ interface ISession {
/**
* onPointerUp:
*
* This method only applies to sensors that are configured as
* This operation only applies to sensors that are configured as
* FingerprintSensorType::UNDER_DISPLAY_*. If invoked for sensors of other types, the HAL must
* treat this as a no-op and return immediately.
*
* This operation can be invoked when the HAL is performing any one of: ISession#authenticate,
* ISession#enroll, ISession#detectInteraction.
*
* @param pointerId See android.view.MotionEvent#getPointerId
*/
void onPointerUp(in int pointerId);
@@ -390,12 +437,15 @@ interface ISession {
/*
* onUiReady:
*
* This method only applies to sensors that are configured as
* This operation only applies to sensors that are configured as
* FingerprintSensorType::UNDER_DISPLAY_OPTICAL. If invoked for sensors of other types, the HAL
* must treat this as a no-op and return immediately.
*
* This operation can be invoked when the HAL is performing any one of: ISession#authenticate,
* ISession#enroll, ISession#detectInteraction.
*
* For FingerprintSensorType::UNDER_DISPLAY_OPTICAL where illumination is handled above the
* HAL, the framework will invoke this method to notify that the illumination has started.
* HAL, the framework will invoke this operation to notify when the illumination is showing.
*/
void onUiReady();
}

View File

@@ -34,12 +34,12 @@ interface ISessionCallback {
/**
* This method must only be used to notify the framework during the following operations:
* 1) ISession#enroll
* 2) ISession#authenticate
* 3) ISession#detectInteraction
* - ISession#enroll
* - ISession#authenticate
* - ISession#detectInteraction
*
* These messages may be used to provide user guidance multiple times if necessary per
* operation.
* These messages may be used to provide user guidance multiple times per operation if
* necessary.
*
* @param info See the AcquiredInfo enum.
* @param vendorCode Only valid if info == AcquiredInfo::VENDOR. The vendorCode must be used to
@@ -51,18 +51,18 @@ interface ISessionCallback {
/**
* This method must only be used to notify the framework during the following operations:
* 1) ISession#enroll
* 2) ISession#authenticate
* 3) ISession#detectInteraction
* 4) ISession#invalidateAuthenticatorId
* 5) ISession#resetLockout
* - ISession#enroll
* - ISession#authenticate
* - ISession#detectInteraction
* - ISession#invalidateAuthenticatorId
* - ISession#resetLockout
*
* These messages may be used to notify the framework or user that a non-recoverable error
* has occurred. The operation is finished, and the HAL can proceed with the next operation
* or return to the idling state.
*
* Note that cancellation (see common::ICancellationSignal) and preemption must be followed with
* an Error::CANCELED message.
* Note that cancellation (see common::ICancellationSignal) must be followed with an
* Error::CANCELED message.
*
* @param error See the Error enum.
* @param vendorCode Only valid if error == Error::VENDOR. The vendorCode must be used to index
@@ -100,8 +100,8 @@ interface ISessionCallback {
* This method must only be used to notify the framework during ISession#authenticate.
*
* Used to notify the framework upon rejected attempts. Note that the authentication
* lifecycle ends when either 1) a fingerprint is accepted, or 2) an occurred. The
* authentication lifecycle does NOT end when a fingerprint is rejected.
* lifecycle ends when either 1) a fingerprint is accepted, or 2) an error occurred.
* The authentication lifecycle does NOT end when a fingerprint is rejected.
*/
void onAuthenticationFailed();

View File

@@ -17,14 +17,19 @@
#pragma once
#include <android-base/logging.h>
#include <random>
namespace aidl::android::hardware::biometrics::fingerprint {
class FakeFingerprintEngine {
public:
FakeFingerprintEngine() : mRandom(std::mt19937::default_seed) {}
void generateChallengeImpl(ISessionCallback* cb) {
LOG(INFO) << "generateChallengeImpl";
cb->onChallengeGenerated(0 /* challenge */);
std::uniform_int_distribution<int64_t> dist;
auto challenge = dist(mRandom);
cb->onChallengeGenerated(challenge);
}
void revokeChallengeImpl(ISessionCallback* cb, int64_t challenge) {
@@ -32,8 +37,13 @@ class FakeFingerprintEngine {
cb->onChallengeRevoked(challenge);
}
void enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& /*hat*/) {
void enrollImpl(ISessionCallback* cb, const keymaster::HardwareAuthToken& hat) {
LOG(INFO) << "enrollImpl";
// Do proper HAT verification in the real implementation.
if (hat.mac.empty()) {
cb->onError(Error::UNABLE_TO_PROCESS, 0 /* vendorError */);
return;
}
cb->onEnrollmentProgress(0 /* enrollmentId */, 0 /* remaining */);
}
@@ -71,6 +81,8 @@ class FakeFingerprintEngine {
LOG(INFO) << "resetLockoutImpl";
cb->onLockoutCleared();
}
std::mt19937 mRandom;
};
} // namespace aidl::android::hardware::biometrics::fingerprint

View File

@@ -35,13 +35,19 @@ constexpr int kUserId = 0;
class SessionCallback : public BnSessionCallback {
public:
explicit SessionCallback(std::promise<void>&& promise) : mPromise(std::move(promise)) {}
ndk::ScopedAStatus onChallengeGenerated(int64_t /*challenge*/) override {
ndk::ScopedAStatus onChallengeGenerated(int64_t challenge) override {
auto lock = std::lock_guard{mMutex};
mOnChallengeGeneratedInvoked = true;
mGeneratedChallenge = challenge;
mCv.notify_one();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus onChallengeRevoked(int64_t /*challenge*/) override {
ndk::ScopedAStatus onChallengeRevoked(int64_t challenge) override {
auto lock = std::lock_guard{mMutex};
mOnChallengeRevokedInvoked = true;
mRevokedChallenge = challenge;
mCv.notify_one();
return ndk::ScopedAStatus::ok();
}
@@ -49,7 +55,11 @@ class SessionCallback : public BnSessionCallback {
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus onError(Error /*error*/, int32_t /*vendorCode*/) override {
ndk::ScopedAStatus onError(Error error, int32_t /*vendorCode*/) override {
auto lock = std::lock_guard{mMutex};
mError = error;
mOnErrorInvoked = true;
mCv.notify_one();
return ndk::ScopedAStatus::ok();
}
@@ -77,63 +87,203 @@ class SessionCallback : public BnSessionCallback {
ndk::ScopedAStatus onEnrollmentsEnumerated(
const std::vector<int32_t>& /*enrollmentIds*/) override {
auto lock = std::lock_guard{mMutex};
mOnEnrollmentsEnumeratedInvoked = true;
mCv.notify_one();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus onEnrollmentsRemoved(
const std::vector<int32_t>& /*enrollmentIds*/) override {
auto lock = std::lock_guard{mMutex};
mOnEnrollmentsRemovedInvoked = true;
mCv.notify_one();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus onAuthenticatorIdRetrieved(int64_t /*authenticatorId*/) override {
auto lock = std::lock_guard{mMutex};
mOnAuthenticatorIdRetrievedInvoked = true;
mCv.notify_one();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus onAuthenticatorIdInvalidated(int64_t /*newAuthenticatorId*/) override {
auto lock = std::lock_guard{mMutex};
mOnAuthenticatorIdInvalidatedInvoked = true;
mCv.notify_one();
return ndk::ScopedAStatus::ok();
}
ndk::ScopedAStatus onSessionClosed() override {
mPromise.set_value();
auto lock = std::lock_guard{mMutex};
mOnSessionClosedInvoked = true;
mCv.notify_one();
return ndk::ScopedAStatus::ok();
}
private:
std::promise<void> mPromise;
std::mutex mMutex;
std::condition_variable mCv;
Error mError = Error::UNKNOWN;
int64_t mGeneratedChallenge = 0;
int64_t mRevokedChallenge = 0;
bool mOnChallengeGeneratedInvoked = false;
bool mOnChallengeRevokedInvoked = false;
bool mOnErrorInvoked = false;
bool mOnEnrollmentsEnumeratedInvoked = false;
bool mOnEnrollmentsRemovedInvoked = false;
bool mOnAuthenticatorIdRetrievedInvoked = false;
bool mOnAuthenticatorIdInvalidatedInvoked = false;
bool mOnSessionClosedInvoked = false;
};
class Fingerprint : public testing::TestWithParam<std::string> {
protected:
void SetUp() override {
AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
ASSERT_NE(binder, nullptr);
mHal = IFingerprint::fromBinder(ndk::SpAIBinder(binder));
// Prepare the callback.
mCb = ndk::SharedRefBase::make<SessionCallback>();
int retries = 0;
bool isOk = false;
// If the first attempt to create a session fails, we try to create a session again. The
// first attempt might fail if the framework already has an active session. The AIDL
// contract doesn't allow to create a new session without closing the old one. However, we
// can't close the framework's session from VTS. The expectation here is that the HAL will
// crash after the first illegal attempt to create a session, then it will restart, and then
// we'll be able to create a session.
do {
// Get an instance of the HAL.
AIBinder* binder = AServiceManager_waitForService(GetParam().c_str());
ASSERT_NE(binder, nullptr);
mHal = IFingerprint::fromBinder(ndk::SpAIBinder(binder));
// Create a session.
isOk = mHal->createSession(kSensorId, kUserId, mCb, &mSession).isOk();
++retries;
} while (!isOk && retries < 2);
ASSERT_TRUE(isOk);
}
void TearDown() override {
// Close the mSession.
ASSERT_TRUE(mSession->close().isOk());
// Make sure the mSession is closed.
auto lock = std::unique_lock<std::mutex>(mCb->mMutex);
mCb->mCv.wait(lock, [this] { return mCb->mOnSessionClosedInvoked; });
}
std::shared_ptr<IFingerprint> mHal;
std::shared_ptr<SessionCallback> mCb;
std::shared_ptr<ISession> mSession;
};
TEST_P(Fingerprint, AuthenticateTest) {
auto promise = std::promise<void>{};
auto future = promise.get_future();
// Prepare the callback.
auto cb = ndk::SharedRefBase::make<SessionCallback>(std::move(promise));
TEST_P(Fingerprint, GetSensorPropsWorksTest) {
std::vector<SensorProps> sensorProps;
// Create a session
std::shared_ptr<ISession> session;
ASSERT_TRUE(mHal->createSession(kSensorId, kUserId, cb, &session).isOk());
// Call the method.
ASSERT_TRUE(mHal->getSensorProps(&sensorProps).isOk());
// Call authenticate
// Make sure the sensorProps aren't empty.
ASSERT_FALSE(sensorProps.empty());
ASSERT_FALSE(sensorProps[0].commonProps.componentInfo.empty());
}
TEST_P(Fingerprint, EnrollWithBadHatResultsInErrorTest) {
// Call the method.
auto hat = keymaster::HardwareAuthToken{};
std::shared_ptr<common::ICancellationSignal> cancellationSignal;
ASSERT_TRUE(session->authenticate(-1 /* operationId */, &cancellationSignal).isOk());
ASSERT_TRUE(mSession->enroll(hat, &cancellationSignal).isOk());
// Get the results
// TODO(b/166799066): test authenticate.
// Make sure an error is returned.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnErrorInvoked; });
}
// Close the session
ASSERT_TRUE(session->close().isOk());
auto status = future.wait_for(1s);
ASSERT_EQ(status, std::future_status::ready);
TEST_P(Fingerprint, GenerateChallengeProducesUniqueChallengesTest) {
static constexpr int kIterations = 100;
auto challenges = std::set<int>{};
for (unsigned int i = 0; i < kIterations; ++i) {
// Call the method.
ASSERT_TRUE(mSession->generateChallenge().isOk());
// Check that the generated challenge is unique and not 0.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeGeneratedInvoked; });
ASSERT_NE(mCb->mGeneratedChallenge, 0);
ASSERT_EQ(challenges.find(mCb->mGeneratedChallenge), challenges.end());
challenges.insert(mCb->mGeneratedChallenge);
mCb->mOnChallengeGeneratedInvoked = false;
}
}
TEST_P(Fingerprint, RevokeChallengeWorksForNonexistentChallengeTest) {
const int64_t nonexistentChallenge = 123;
// Call the method.
ASSERT_TRUE(mSession->revokeChallenge(nonexistentChallenge).isOk());
// Check that the challenge is revoked and matches the requested challenge.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeRevokedInvoked; });
ASSERT_EQ(mCb->mRevokedChallenge, nonexistentChallenge);
}
TEST_P(Fingerprint, RevokeChallengeWorksForExistentChallengeTest) {
// Generate a challenge.
ASSERT_TRUE(mSession->generateChallenge().isOk());
// Wait for the result.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeGeneratedInvoked; });
lock.unlock();
// Revoke the challenge.
ASSERT_TRUE(mSession->revokeChallenge(mCb->mGeneratedChallenge).isOk());
// Check that the challenge is revoked and matches the requested challenge.
lock.lock();
mCb->mCv.wait(lock, [this] { return mCb->mOnChallengeRevokedInvoked; });
ASSERT_EQ(mCb->mRevokedChallenge, mCb->mGeneratedChallenge);
}
TEST_P(Fingerprint, EnumerateEnrollmentsWorksTest) {
// Call the method.
ASSERT_TRUE(mSession->enumerateEnrollments().isOk());
// Wait for the result.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnEnrollmentsEnumeratedInvoked; });
}
TEST_P(Fingerprint, RemoveEnrollmentsWorksTest) {
// Call the method.
ASSERT_TRUE(mSession->removeEnrollments({}).isOk());
// Wait for the result.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnEnrollmentsRemovedInvoked; });
}
TEST_P(Fingerprint, GetAuthenticatorIdWorksTest) {
// Call the method.
ASSERT_TRUE(mSession->getAuthenticatorId().isOk());
// Wait for the result.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnAuthenticatorIdRetrievedInvoked; });
}
TEST_P(Fingerprint, InvalidateAuthenticatorIdWorksTest) {
// Call the method.
ASSERT_TRUE(mSession->invalidateAuthenticatorId().isOk());
// Wait for the result.
auto lock = std::unique_lock{mCb->mMutex};
mCb->mCv.wait(lock, [this] { return mCb->mOnAuthenticatorIdInvalidatedInvoked; });
}
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(Fingerprint);

View File

@@ -32,10 +32,14 @@ namespace implementation {
using ::android::bluetooth::audio::BluetoothAudioSessionReport;
using ::android::hardware::Void;
// Here the buffer size is based on SBC
static constexpr uint32_t kPcmFrameSize = 4; // 16 bits per sample / stereo
static constexpr uint32_t kPcmFrameCount = 128;
// SBC is 128, and here choose the LCM of 16, 24, and 32
static constexpr uint32_t kPcmFrameCount = 96;
static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
static constexpr uint32_t kRtpFrameCount = 7; // max counts by 1 tick (20ms)
// The max counts by 1 tick (20ms) for SBC is about 7. Since using 96 for the
// PCM counts, here we just choose a greater number
static constexpr uint32_t kRtpFrameCount = 10;
static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
static constexpr uint32_t kBufferCount = 2; // double buffer
static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;

View File

@@ -34,10 +34,14 @@ using ::android::bluetooth::audio::BluetoothAudioSessionReport_2_1;
using ::android::hardware::Void;
using ::android::hardware::bluetooth::audio::V2_0::AudioConfiguration;
// Here the buffer size is based on SBC
static constexpr uint32_t kPcmFrameSize = 4; // 16 bits per sample / stereo
static constexpr uint32_t kPcmFrameCount = 128;
// SBC is 128, and here we choose the LCM of 16, 24, and 32
static constexpr uint32_t kPcmFrameCount = 96;
static constexpr uint32_t kRtpFrameSize = kPcmFrameSize * kPcmFrameCount;
static constexpr uint32_t kRtpFrameCount = 7; // max counts by 1 tick (20ms)
// The max counts by 1 tick (20ms) for SBC is about 7. Since using 96 for the
// PCM counts, here we just choose a greater number
static constexpr uint32_t kRtpFrameCount = 10;
static constexpr uint32_t kBufferSize = kRtpFrameSize * kRtpFrameCount;
static constexpr uint32_t kBufferCount = 2; // double buffer
static constexpr uint32_t kDataMqSize = kBufferSize * kBufferCount;

View File

@@ -42,7 +42,7 @@ struct Stream {
/**
* The surface group id used for multi-resolution output streams.
*
* This works simliar to the surfaceGroupId of OutputConfiguration in the
* This works similar to the surfaceGroupId of OutputConfiguration in the
* public API, with the exception that this is for multi-resolution image
* reader and is used by the camera HAL to choose a target stream within
* the same group to which images are written. All streams in the same group

View File

@@ -686,7 +686,9 @@ enum CameraMetadataTag : uint32_t {
/** android.jpeg.maxSize [static, int32, system]
*
* <p>Maximum size in bytes for the compressed
* JPEG buffer</p>
* JPEG buffer, in default sensor pixel mode (see ANDROID_SENSOR_PIXEL_MODE)</p>
*
* @see ANDROID_SENSOR_PIXEL_MODE
*/
ANDROID_JPEG_MAX_SIZE,

View File

@@ -230,10 +230,10 @@ namespace {
return false;
}
int getCameraDeviceVersion(const hidl_string& deviceName,
const hidl_string &providerType) {
int getCameraDeviceVersionAndId(const hidl_string& deviceName,
const hidl_string &providerType, std::string* id) {
std::string version;
bool match = matchDeviceName(deviceName, providerType, &version, nullptr);
bool match = matchDeviceName(deviceName, providerType, &version, id);
if (!match) {
return -1;
}
@@ -256,6 +256,11 @@ namespace {
return 0;
}
int getCameraDeviceVersion(const hidl_string& deviceName,
const hidl_string &providerType) {
return getCameraDeviceVersionAndId(deviceName, providerType, nullptr);
}
bool parseProviderName(const std::string& name, std::string *type /*out*/,
uint32_t *id /*out*/) {
if (!type || !id) {
@@ -930,6 +935,7 @@ public:
camera_metadata_ro_entry* streamConfigs,
camera_metadata_ro_entry* maxResolutionStreamConfigs,
const camera_metadata_t* staticMetadata);
static bool isColorCamera(const camera_metadata_t *metadata);
static V3_2::DataspaceFlags getDataspace(PixelFormat format);
@@ -6179,6 +6185,167 @@ TEST_P(CameraHidlTest, configureInjectionStreamsWithSessionParameters) {
}
}
// Test the multi-camera API requirement for Google Requirement Freeze S
// Note that this requirement can only be partially tested. If a vendor
// device doesn't expose a physical camera in any shape or form, there is no way
// the test can catch it.
TEST_P(CameraHidlTest, grfSMultiCameraTest) {
const int socGrfApi = property_get_int32("ro.board.first_api_level", /*default*/ -1);
if (socGrfApi < 31 /*S*/) {
// Non-GRF devices, or version < 31 Skip
ALOGI("%s: socGrfApi level is %d. Skipping", __FUNCTION__, socGrfApi);
return;
}
// Test that if more than one color cameras facing the same direction are
// supported, there must be at least one logical camera facing that
// direction.
hidl_vec<hidl_string> cameraDeviceNames = getCameraDeviceNames(mProvider);
// Front and back facing non-logical color cameras
std::set<std::string> frontColorCameras, rearColorCameras;
// Front and back facing logical cameras' physical camera Id sets
std::set<std::set<std::string>> frontPhysicalIds, rearPhysicalIds;
for (const auto& name : cameraDeviceNames) {
std::string cameraId;
int deviceVersion = getCameraDeviceVersionAndId(name, mProviderType, &cameraId);
switch (deviceVersion) {
case CAMERA_DEVICE_API_VERSION_3_7:
case CAMERA_DEVICE_API_VERSION_3_6:
case CAMERA_DEVICE_API_VERSION_3_5:
case CAMERA_DEVICE_API_VERSION_3_4:
case CAMERA_DEVICE_API_VERSION_3_3:
case CAMERA_DEVICE_API_VERSION_3_2: {
::android::sp<::android::hardware::camera::device::V3_2::ICameraDevice> device3_x;
ALOGI("getCameraCharacteristics: Testing camera device %s", name.c_str());
Return<void> ret;
ret = mProvider->getCameraDeviceInterface_V3_x(
name, [&](auto status, const auto& device) {
ALOGI("getCameraDeviceInterface_V3_x returns status:%d", (int)status);
ASSERT_EQ(Status::OK, status);
ASSERT_NE(device, nullptr);
device3_x = device;
});
ASSERT_TRUE(ret.isOk());
ret = device3_x->getCameraCharacteristics([&](auto status, const auto& chars) {
ASSERT_EQ(Status::OK, status);
const camera_metadata_t* metadata = (camera_metadata_t*)chars.data();
// Skip if this is not a color camera.
if (!CameraHidlTest::isColorCamera(metadata)) {
return;
}
// Check camera facing. Skip if facing is neither FRONT
// nor BACK. If this is not a logical camera, only note down
// the camera ID, and skip.
camera_metadata_ro_entry entry;
int retcode = find_camera_metadata_ro_entry(
metadata, ANDROID_LENS_FACING, &entry);
ASSERT_EQ(retcode, 0);
ASSERT_GT(entry.count, 0);
uint8_t facing = entry.data.u8[0];
bool isLogicalCamera = (isLogicalMultiCamera(metadata) == Status::OK);
if (facing == ANDROID_LENS_FACING_FRONT) {
if (!isLogicalCamera) {
frontColorCameras.insert(cameraId);
return;
}
} else if (facing == ANDROID_LENS_FACING_BACK) {
if (!isLogicalCamera) {
rearColorCameras.insert(cameraId);
return;
}
} else {
// Not FRONT or BACK facing. Skip.
return;
}
// Check logical camera's physical camera IDs for color
// cameras.
std::unordered_set<std::string> physicalCameraIds;
Status s = getPhysicalCameraIds(metadata, &physicalCameraIds);
ASSERT_EQ(Status::OK, s);
if (facing == ANDROID_LENS_FACING_FRONT) {
frontPhysicalIds.emplace(physicalCameraIds.begin(), physicalCameraIds.end());
} else {
rearPhysicalIds.emplace(physicalCameraIds.begin(), physicalCameraIds.end());
}
for (const auto& physicalId : physicalCameraIds) {
// Skip if the physicalId is publicly available
for (auto& deviceName : cameraDeviceNames) {
std::string publicVersion, publicId;
ASSERT_TRUE(::matchDeviceName(deviceName, mProviderType,
&publicVersion, &publicId));
if (physicalId == publicId) {
// Skip because public Ids will be iterated in outer loop.
return;
}
}
auto castResult = device::V3_5::ICameraDevice::castFrom(device3_x);
ASSERT_TRUE(castResult.isOk());
::android::sp<::android::hardware::camera::device::V3_5::ICameraDevice>
device3_5 = castResult;
ASSERT_NE(device3_5, nullptr);
// Check camera characteristics for hidden camera id
Return<void> ret = device3_5->getPhysicalCameraCharacteristics(
physicalId, [&](auto status, const auto& chars) {
ASSERT_EQ(Status::OK, status);
const camera_metadata_t* physicalMetadata =
(camera_metadata_t*)chars.data();
if (CameraHidlTest::isColorCamera(physicalMetadata)) {
if (facing == ANDROID_LENS_FACING_FRONT) {
frontColorCameras.insert(physicalId);
} else if (facing == ANDROID_LENS_FACING_BACK) {
rearColorCameras.insert(physicalId);
}
}
});
ASSERT_TRUE(ret.isOk());
}
});
ASSERT_TRUE(ret.isOk());
} break;
case CAMERA_DEVICE_API_VERSION_1_0: {
// Not applicable
} break;
default: {
ALOGE("%s: Unsupported device version %d", __func__, deviceVersion);
ADD_FAILURE();
} break;
}
}
// If there are more than one color cameras facing one direction, a logical
// multi-camera must be defined consisting of all color cameras facing that
// direction.
if (frontColorCameras.size() > 1) {
bool hasFrontLogical = false;
for (const auto& physicalIds : frontPhysicalIds) {
if (std::includes(physicalIds.begin(), physicalIds.end(),
frontColorCameras.begin(), frontColorCameras.end())) {
hasFrontLogical = true;
break;
}
}
ASSERT_TRUE(hasFrontLogical);
}
if (rearColorCameras.size() > 1) {
bool hasRearLogical = false;
for (const auto& physicalIds : rearPhysicalIds) {
if (std::includes(physicalIds.begin(), physicalIds.end(),
rearColorCameras.begin(), rearColorCameras.end())) {
hasRearLogical = true;
break;
}
}
ASSERT_TRUE(hasRearLogical);
}
}
// Retrieve all valid output stream resolutions from the camera
// static characteristics.
Status CameraHidlTest::getAvailableOutputStreams(const camera_metadata_t* staticMeta,
@@ -6651,6 +6818,23 @@ Status CameraHidlTest::isMonochromeCamera(const camera_metadata_t *staticMeta) {
return ret;
}
bool CameraHidlTest::isColorCamera(const camera_metadata_t *metadata) {
camera_metadata_ro_entry entry;
int retcode = find_camera_metadata_ro_entry(
metadata, ANDROID_REQUEST_AVAILABLE_CAPABILITIES, &entry);
if ((0 == retcode) && (entry.count > 0)) {
bool isBackwardCompatible = (std::find(entry.data.u8, entry.data.u8 + entry.count,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_BACKWARD_COMPATIBLE) !=
entry.data.u8 + entry.count);
bool isMonochrome = (std::find(entry.data.u8, entry.data.u8 + entry.count,
ANDROID_REQUEST_AVAILABLE_CAPABILITIES_MONOCHROME) !=
entry.data.u8 + entry.count);
bool isColor = isBackwardCompatible && !isMonochrome;
return isColor;
}
return false;
}
// Retrieve the reprocess input-output format map from the static
// camera characteristics.
Status CameraHidlTest::getZSLInputOutputMap(camera_metadata_t *staticMeta,

View File

@@ -768,6 +768,8 @@ a64467bae843569f0d465c5be7f0c7a5b987985b55a3ef4794dd5afc68538650 android.hardwar
98592d193a717066facf91428426e5abe211e3bd718bc372e29fb944ddbe6e7c android.hardware.wifi.supplicant@1.3::types
# ABI preserving changes to HALs during Android S
# b/193346383
93d29fbe2fcc5e4e053a9db7c9abbd9190c46b85b443f2698a3460db2ee76c8d android.hardware.camera.metadata@3.2::types
159a0069336035852e9eca6354b86b7990680d1b239f23ef2f631b01807c4cb9 android.hardware.camera.metadata@3.5::types
e042522daa4b5f7fd4a0a19bcdadb93c79a1b04c09ef2c9813a3a8941032f3f5 android.hardware.contexthub@1.0::IContexthub
c2f64133b83ede65c9939ef97ab5bd867b73faf3dba0e7e69f77c3c43d9e487e android.hardware.contexthub@1.0::IContexthubCallback
@@ -831,6 +833,7 @@ e3865e74cb1a6e6afd38c7aa84115cb109ce47b972132de5242bc3838d2771f6 android.hardwar
b3caf524c46a47d67e6453a34419e1881942d059e146cda740502670e9a752c3 android.hardware.automotive.vehicle@2.0::IVehicle
7ce8728b27600e840cacf0a832f6942819fe535f9d3797ae052d5eef5065921c android.hardware.automotive.vehicle@2.0::IVehicleCallback
b525e91d886379c13588f4975bb04d625d46e1f41b4453792c4b2db1e7ff4340 android.hardware.biometrics.fingerprint@2.3::IBiometricsFingerprint
7a78e9963bec0b071e7d46928c6100e2174270892d3f15a1eaad074997adf279 android.hardware.biometrics.fingerprint@2.3::IBiometricsFingerprint # Added for b/160189286 for Android S
4baf8e0eca4aa896cc9ceb7bb676aaf4fa21372ef8b49eed68eced1221c3dc0d android.hardware.bluetooth.audio@2.1::IBluetoothAudioProvider
d417a9212c8f96e3a06a2f221c8c5756c765355b2b81de2b2a65d4c9eee85401 android.hardware.bluetooth.audio@2.1::IBluetoothAudioProvidersFactory
c17d9e27abd37ae5a8ff8da08fc5c9b13a264670feef6bbbc9d3ab1915216130 android.hardware.bluetooth.audio@2.1::types
@@ -838,7 +841,7 @@ c17d9e27abd37ae5a8ff8da08fc5c9b13a264670feef6bbbc9d3ab1915216130 android.hardwar
1a1dff6e8d25dbc02a69fed3c077dd0782b30331ca3f345848ec52fc67744224 android.hardware.camera.device@3.7::ICameraDevice
3be6faa3d11ad9c7ec01a1a0a009cf11cb65d701d109dab37613ce9cfb3cdd60 android.hardware.camera.device@3.7::ICameraDeviceSession
3740ec773b2eb8fa6bd8c6e879eedb56c4e4306b88f1c20fa51103d791d871b1 android.hardware.camera.device@3.7::ICameraInjectionSession
21f023685571daf46148097d98b89cea353f07e3ed83b2ed5685b23bd136c3ee android.hardware.camera.device@3.7::types
d272697484c41bbf76a0924d2aaebf065ce37a822fcb438316eb5dd2d112f052 android.hardware.camera.device@3.7::types
e932e7ef95210142e1fd3a4504e1d19bdb1acc988450f1ced543f3401f67855a android.hardware.camera.metadata@3.6::types
98ff825a7d37e5ab983502d13cec1f2e5a9cac9b674b6ff1a52bcf540f4e315e android.hardware.camera.provider@2.7::ICameraProvider
51fd14005859b16be55872660c34f5d423c77a2abcc5d4bdd5a537c40f32516b android.hardware.camera.provider@2.7::types

View File

@@ -1,9 +1,9 @@
#define LOG_TAG "Gnss"
#include "Gnss.h"
#include <android/hardware/gnss/1.0/types.h>
#include <log/log.h>
#include "Gnss.h"
#include "Constants.h"
#include "GnssDebug.h"
#include "GnssMeasurement.h"
#include "Utils.h"
@@ -16,6 +16,7 @@ namespace implementation {
using ::android::hardware::gnss::common::Utils;
using GnssSvFlags = IGnssCallback::GnssSvFlags;
using namespace ::android::hardware::gnss::common;
const uint32_t MIN_INTERVAL_MILLIS = 100;
sp<::android::hardware::gnss::V1_1::IGnssCallback> Gnss::sGnssCallback = nullptr;
@@ -197,14 +198,21 @@ Return<bool> Gnss::injectBestLocation(const GnssLocation&) {
Return<GnssSvStatus> Gnss::getMockSvStatus() const {
std::unique_lock<std::recursive_mutex> lock(mGnssConfiguration->getMutex());
GnssSvInfo mockGnssSvInfoList[] = {
Utils::getMockSvInfoV1_0(3, GnssConstellationType::GPS, 32.5, 59.1, 166.5),
Utils::getMockSvInfoV1_0(5, GnssConstellationType::GPS, 27.0, 29.0, 56.5),
Utils::getMockSvInfoV1_0(17, GnssConstellationType::GPS, 30.5, 71.0, 77.0),
Utils::getMockSvInfoV1_0(26, GnssConstellationType::GPS, 24.1, 28.0, 253.0),
Utils::getMockSvInfoV1_0(5, GnssConstellationType::GLONASS, 20.5, 11.5, 116.0),
Utils::getMockSvInfoV1_0(17, GnssConstellationType::GLONASS, 21.5, 28.5, 186.0),
Utils::getMockSvInfoV1_0(18, GnssConstellationType::GLONASS, 28.3, 38.8, 69.0),
Utils::getMockSvInfoV1_0(10, GnssConstellationType::GLONASS, 25.0, 66.0, 247.0)};
Utils::getMockSvInfoV1_0(3, GnssConstellationType::GPS, 32.5, 59.1, 166.5,
kGpsL1FreqHz),
Utils::getMockSvInfoV1_0(5, GnssConstellationType::GPS, 27.0, 29.0, 56.5, kGpsL1FreqHz),
Utils::getMockSvInfoV1_0(17, GnssConstellationType::GPS, 30.5, 71.0, 77.0,
kGpsL5FreqHz),
Utils::getMockSvInfoV1_0(26, GnssConstellationType::GPS, 24.1, 28.0, 253.0,
kGpsL5FreqHz),
Utils::getMockSvInfoV1_0(5, GnssConstellationType::GLONASS, 20.5, 11.5, 116.0,
kGloG1FreqHz),
Utils::getMockSvInfoV1_0(17, GnssConstellationType::GLONASS, 21.5, 28.5, 186.0,
kGloG1FreqHz),
Utils::getMockSvInfoV1_0(18, GnssConstellationType::GLONASS, 28.3, 38.8, 69.0,
kGloG1FreqHz),
Utils::getMockSvInfoV1_0(10, GnssConstellationType::GLONASS, 25.0, 66.0, 247.0,
kGloG1FreqHz)};
GnssSvStatus svStatus = {.numSvs = sizeof(mockGnssSvInfoList) / sizeof(GnssSvInfo)};
for (uint32_t i = 0; i < svStatus.numSvs; i++) {

View File

@@ -249,35 +249,40 @@ TEST_P(GnssHalTest, TestGnssAntennaInfo) {
/*
* TestGnssSvInfoFields:
* Gets 1 location and a GnssSvInfo, and verifies
* 1. basebandCN0DbHz is valid.
* Gets 1 location and a (non-empty) GnssSvInfo, and verifies basebandCN0DbHz is valid.
*/
TEST_P(GnssHalTest, TestGnssSvInfoFields) {
gnss_cb_->location_cbq_.reset();
gnss_cb_->sv_info_list_cbq_.reset();
StartAndCheckFirstLocation(/* min_interval_msec= */ 1000, /* low_power_mode= */ false);
int location_called_count = gnss_cb_->location_cbq_.calledCount();
// Tolerate 1 less sv status to handle edge cases in reporting.
int sv_info_list_cbq_size = gnss_cb_->sv_info_list_cbq_.size();
EXPECT_GE(sv_info_list_cbq_size, 0);
ALOGD("Observed %d GnssSvStatus, while awaiting one location (%d received)",
sv_info_list_cbq_size, location_called_count);
gnss_cb_->sv_info_list_cbq_.size(), location_called_count);
// Get the last sv_info_list
std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_vec_list;
gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_vec_list, sv_info_list_cbq_size, 1);
hidl_vec<IGnssCallback_2_1::GnssSvInfo> last_sv_info_list = sv_info_vec_list.back();
// Wait for up to kNumSvInfoLists events for kTimeoutSeconds for each event.
int kTimeoutSeconds = 2;
int kNumSvInfoLists = 4;
std::list<hidl_vec<IGnssCallback_2_1::GnssSvInfo>> sv_info_lists;
hidl_vec<IGnssCallback_2_1::GnssSvInfo> last_sv_info_list;
do {
EXPECT_GT(gnss_cb_->sv_info_list_cbq_.retrieve(sv_info_lists, kNumSvInfoLists,
kTimeoutSeconds),
0);
last_sv_info_list = sv_info_lists.back();
} while (last_sv_info_list.size() == 0);
ALOGD("last_sv_info size = %d", (int)last_sv_info_list.size());
bool nonZeroCn0Found = false;
for (auto sv_info : last_sv_info_list) {
ASSERT_TRUE(sv_info.basebandCN0DbHz >= 0.0 && sv_info.basebandCN0DbHz <= 65.0);
EXPECT_TRUE(sv_info.basebandCN0DbHz >= 0.0 && sv_info.basebandCN0DbHz <= 65.0);
if (sv_info.basebandCN0DbHz > 0.0) {
nonZeroCn0Found = true;
}
}
// Assert at least one value is non-zero. Zero is ok in status as it's possibly
// reporting a searched but not found satellite.
ASSERT_TRUE(nonZeroCn0Found);
EXPECT_TRUE(nonZeroCn0Found);
StopAndClearLocations();
}

View File

@@ -265,50 +265,50 @@ V1_0::GnssLocation Utils::getMockLocationV1_0() {
}
hidl_vec<GnssSvInfoV2_1> Utils::getMockSvInfoListV2_1() {
GnssSvInfoV1_0 gnssSvInfoV1_0 =
Utils::getMockSvInfoV1_0(3, V1_0::GnssConstellationType::GPS, 32.5, 59.1, 166.5);
GnssSvInfoV1_0 gnssSvInfoV1_0 = Utils::getMockSvInfoV1_0(3, V1_0::GnssConstellationType::GPS,
32.5, 59.1, 166.5, kGpsL1FreqHz);
GnssSvInfoV2_0 gnssSvInfoV2_0 =
Utils::getMockSvInfoV2_0(gnssSvInfoV1_0, V2_0::GnssConstellationType::GPS);
hidl_vec<GnssSvInfoV2_1> gnssSvInfoList = {
Utils::getMockSvInfoV2_1(gnssSvInfoV2_0, 27.5),
getMockSvInfoV2_1(
getMockSvInfoV2_0(getMockSvInfoV1_0(5, V1_0::GnssConstellationType::GPS, 27.0,
29.0, 56.5),
29.0, 56.5, kGpsL1FreqHz),
V2_0::GnssConstellationType::GPS),
22.0),
getMockSvInfoV2_1(
getMockSvInfoV2_0(getMockSvInfoV1_0(17, V1_0::GnssConstellationType::GPS, 30.5,
71.0, 77.0),
71.0, 77.0, kGpsL5FreqHz),
V2_0::GnssConstellationType::GPS),
25.5),
getMockSvInfoV2_1(
getMockSvInfoV2_0(getMockSvInfoV1_0(26, V1_0::GnssConstellationType::GPS, 24.1,
28.0, 253.0),
28.0, 253.0, kGpsL5FreqHz),
V2_0::GnssConstellationType::GPS),
19.1),
getMockSvInfoV2_1(
getMockSvInfoV2_0(getMockSvInfoV1_0(5, V1_0::GnssConstellationType::GLONASS,
20.5, 11.5, 116.0),
20.5, 11.5, 116.0, kGloG1FreqHz),
V2_0::GnssConstellationType::GLONASS),
15.5),
getMockSvInfoV2_1(
getMockSvInfoV2_0(getMockSvInfoV1_0(17, V1_0::GnssConstellationType::GLONASS,
21.5, 28.5, 186.0),
21.5, 28.5, 186.0, kGloG1FreqHz),
V2_0::GnssConstellationType::GLONASS),
16.5),
getMockSvInfoV2_1(
getMockSvInfoV2_0(getMockSvInfoV1_0(18, V1_0::GnssConstellationType::GLONASS,
28.3, 38.8, 69.0),
28.3, 38.8, 69.0, kGloG1FreqHz),
V2_0::GnssConstellationType::GLONASS),
25.3),
getMockSvInfoV2_1(
getMockSvInfoV2_0(getMockSvInfoV1_0(10, V1_0::GnssConstellationType::GLONASS,
25.0, 66.0, 247.0),
25.0, 66.0, 247.0, kGloG1FreqHz),
V2_0::GnssConstellationType::GLONASS),
20.0),
getMockSvInfoV2_1(
getMockSvInfoV2_0(getMockSvInfoV1_0(3, V1_0::GnssConstellationType::UNKNOWN,
22.0, 35.0, 112.0),
22.0, 35.0, 112.0, kIrnssL5FreqHz),
V2_0::GnssConstellationType::IRNSS),
19.7),
};
@@ -333,21 +333,23 @@ GnssSvInfoV2_0 Utils::getMockSvInfoV2_0(GnssSvInfoV1_0 gnssSvInfoV1_0,
}
GnssSvInfoV1_0 Utils::getMockSvInfoV1_0(int16_t svid, V1_0::GnssConstellationType type,
float cN0DbHz, float elevationDegrees,
float azimuthDegrees) {
float cN0DbHz, float elevationDegrees, float azimuthDegrees,
float carrierFrequencyHz) {
GnssSvInfoV1_0 svInfo = {.svid = svid,
.constellation = type,
.cN0Dbhz = cN0DbHz,
.elevationDegrees = elevationDegrees,
.azimuthDegrees = azimuthDegrees,
.carrierFrequencyHz = carrierFrequencyHz,
.svFlag = GnssSvFlags::USED_IN_FIX | GnssSvFlags::HAS_EPHEMERIS_DATA |
GnssSvFlags::HAS_ALMANAC_DATA};
GnssSvFlags::HAS_ALMANAC_DATA |
GnssSvFlags::HAS_CARRIER_FREQUENCY};
return svInfo;
}
hidl_vec<GnssAntennaInfo> Utils::getMockAntennaInfos() {
GnssAntennaInfo mockAntennaInfo_1 = {
.carrierFrequencyMHz = 123412.12,
.carrierFrequencyMHz = kGpsL1FreqHz * 1e-6,
.phaseCenterOffsetCoordinateMillimeters = Coord{.x = 1,
.xUncertainty = 0.1,
.y = 2,
@@ -381,7 +383,7 @@ hidl_vec<GnssAntennaInfo> Utils::getMockAntennaInfos() {
};
GnssAntennaInfo mockAntennaInfo_2 = {
.carrierFrequencyMHz = 532324.23,
.carrierFrequencyMHz = kGpsL5FreqHz * 1e-6,
.phaseCenterOffsetCoordinateMillimeters = Coord{.x = 5,
.xUncertainty = 0.1,
.y = 6,

View File

@@ -29,6 +29,10 @@ const float kMockVerticalAccuracyMeters = 5;
const float kMockSpeedAccuracyMetersPerSecond = 1;
const float kMockBearingAccuracyDegrees = 90;
const int64_t kMockTimestamp = 1519930775453L;
const float kGpsL1FreqHz = 1575.42 * 1e6;
const float kGpsL5FreqHz = 1176.45 * 1e6;
const float kGloG1FreqHz = 1602.0 * 1e6;
const float kIrnssL5FreqHz = 1176.45 * 1e6;
} // namespace common
} // namespace gnss

View File

@@ -44,7 +44,8 @@ struct Utils {
static V1_0::IGnssCallback::GnssSvInfo getMockSvInfoV1_0(int16_t svid,
V1_0::GnssConstellationType type,
float cN0DbHz, float elevationDegrees,
float azimuthDegrees);
float azimuthDegrees,
float carrierFrequencyHz);
static hidl_vec<V2_1::IGnssAntennaInfoCallback::GnssAntennaInfo> getMockAntennaInfos();
};

View File

@@ -113,6 +113,7 @@ struct GnssTemplate : public T_IGnss {
void reportLocation(const V2_0::GnssLocation&) const;
void reportLocation(const V1_0::GnssLocation&) const;
void reportSvStatus(const hidl_vec<V2_1::IGnssCallback::GnssSvInfo>&) const;
void reportGnssStatusValue(const V1_0::IGnssCallback::GnssStatusValue) const;
Return<void> help(const hidl_handle& fd);
Return<void> setLocation(const hidl_handle& fd, const hidl_vec<hidl_string>& options);
@@ -215,6 +216,7 @@ Return<bool> GnssTemplate<T_IGnss>::start() {
}
mIsActive = true;
this->reportGnssStatusValue(V1_0::IGnssCallback::GnssStatusValue::SESSION_BEGIN);
mThread = std::thread([this]() {
while (mIsActive == true) {
auto svStatus = filterBlocklistedSatellitesV2_1(Utils::getMockSvInfoListV2_1());
@@ -266,6 +268,7 @@ template <class T_IGnss>
Return<bool> GnssTemplate<T_IGnss>::stop() {
ALOGD("stop");
mIsActive = false;
this->reportGnssStatusValue(V1_0::IGnssCallback::GnssStatusValue::SESSION_END);
if (mThread.joinable()) {
mThread.join();
}
@@ -605,6 +608,20 @@ Return<sp<V2_1::IGnssAntennaInfo>> GnssTemplate<T_IGnss>::getExtensionGnssAntenn
return new V2_1::implementation::GnssAntennaInfo();
}
template <class T_IGnss>
void GnssTemplate<T_IGnss>::reportGnssStatusValue(
const V1_0::IGnssCallback::GnssStatusValue gnssStatusValue) const {
std::unique_lock<std::mutex> lock(mMutex);
if (sGnssCallback_2_1 == nullptr) {
ALOGE("%s: sGnssCallback v2.1 is null.", __func__);
return;
}
auto ret = sGnssCallback_2_1->gnssStatusCb(gnssStatusValue);
if (!ret.isOk()) {
ALOGE("%s: Unable to invoke callback", __func__);
}
}
template <class T_IGnss>
void GnssTemplate<T_IGnss>::reportSvStatus(
const hidl_vec<V2_1::IGnssCallback::GnssSvInfo>& svInfoList) const {

View File

@@ -458,6 +458,7 @@ TEST_P(GraphicsCompositionTest, ClientComposition) {
<< " pixel format: PixelFormat::RGBA_8888 dataspace: "
<< ReadbackHelper::getDataspaceString(clientDataspace)
<< " unsupported for display" << std::endl;
mReader->mCompositionChanges.clear();
continue;
}

View File

@@ -17,6 +17,7 @@
#define LOG_TAG "graphics_composer_hidl_hal_test@2.3"
#include <algorithm>
#include <numeric>
#include <android-base/logging.h>
#include <android-base/properties.h>
@@ -155,16 +156,31 @@ class GraphicsComposerHidlCommandTest : public GraphicsComposerHidlTest {
TEST_P(GraphicsComposerHidlTest, GetDisplayIdentificationData) {
uint8_t port0;
std::vector<uint8_t> data0;
if (mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port0, &data0)) {
uint8_t port1;
std::vector<uint8_t> data1;
ASSERT_TRUE(mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port1, &data1));
ASSERT_EQ(port0, port1) << "ports are not stable";
ASSERT_TRUE(data0.size() == data1.size() &&
std::equal(data0.begin(), data0.end(), data1.begin()))
<< "data is not stable";
if (!mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port0, &data0)) {
return;
}
ASSERT_FALSE(data0.empty());
constexpr size_t kEdidBlockSize = 128;
ASSERT_TRUE(data0.size() % kEdidBlockSize == 0)
<< "EDID blob length is not a multiple of " << kEdidBlockSize;
const uint8_t kEdidHeader[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
ASSERT_TRUE(std::equal(std::begin(kEdidHeader), std::end(kEdidHeader), data0.begin()))
<< "EDID blob doesn't start with the fixed EDID header";
ASSERT_EQ(0, std::accumulate(data0.begin(), data0.begin() + kEdidBlockSize,
static_cast<uint8_t>(0)))
<< "EDID base block doesn't checksum";
uint8_t port1;
std::vector<uint8_t> data1;
ASSERT_TRUE(mComposerClient->getDisplayIdentificationData(mPrimaryDisplay, &port1, &data1));
ASSERT_EQ(port0, port1) << "ports are not stable";
ASSERT_TRUE(data0.size() == data1.size() &&
std::equal(data0.begin(), data0.end(), data1.begin()))
<< "data is not stable";
}
/**

View File

@@ -31,6 +31,6 @@
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="VtsHalGraphicsComposerV2_4TargetTest" />
<option name="native-test-timeout" value="300000"/>
<option name="native-test-timeout" value="900000"/>
</test>
</configuration>

View File

@@ -438,7 +438,7 @@ bool verify_attestation_record(const string& challenge, const string& app_id,
// TODO(b/136282179): When running under VTS-on-GSI the TEE-backed
// keymaster implementation will report YYYYMM dates instead of YYYYMMDD
// for the BOOT_PATCH_LEVEL.
if (avb_verification_enabled()) {
if (!is_gsi()) {
for (int i = 0; i < att_hw_enforced.size(); i++) {
if (att_hw_enforced[i].tag == TAG_BOOT_PATCHLEVEL ||
att_hw_enforced[i].tag == TAG_VENDOR_PATCHLEVEL) {

View File

@@ -31,21 +31,36 @@ import android.hardware.memtrack.MemtrackType;
* accounting for stride, bit depth, rounding up to page size, etc.
*
* The following getMemory() categories are important for memory accounting in
* `dumpsys meminfo` and should be reported as described below:
* Android frameworks (e.g. `dumpsys meminfo`) and should be reported as described
* below:
*
* - MemtrackType::GRAPHICS and MemtrackRecord::FLAG_SMAPS_UNACCOUNTED
* This should report the PSS of all DMA buffers mapped by the process
* with the specified PID. This PSS can be calculated using ReadDmaBufPss()
* form libdmabufinfo.
* This should report the PSS of all CPU-Mapped DMA-BUFs (buffers mapped into
* the process address space) and all GPU-Mapped DMA-BUFs (buffers mapped into
* the GPU device address space on behalf of the process), removing any overlap
* between the CPU-mapped and GPU-mapped sets.
*
* - MemtrackType::GL and MemtrackRecord::FLAG_SMAPS_UNACCOUNTED
* This category should report all GPU private allocations for the specified
* PID that are not accounted in /proc/<pid>/smaps.
*
* getMemory() called with PID 0 should report the global total GPU-private
* memory, for MemtrackType::GL and MemtrackRecord::FLAG_SMAPS_UNACCOUNTED.
*
* getMemory() called with PID 0 for a MemtrackType other than GL should
* report 0.
*
* - MemtrackType::OTHER and MemtrackRecord::FLAG_SMAPS_UNACCOUNTED
* Any other memory not accounted for in /proc/<pid>/smaps if any, otherwise
* this should return 0.
*
* SMAPS_UNACCOUNTED memory should also include memory that is mapped with
* VM_PFNMAP flag set. For these mappings PSS and RSS are reported as 0 in smaps.
* Such mappings have no backing page structs from which PSS/RSS can be calculated.
*
* Any memtrack operation that is not supported should return a binder status with
* exception code EX_UNSUPPORTED_OPERATION.
*
* Constructor for the interface should be used to perform memtrack management
* setup actions and must be called once before any calls to getMemory().
*/

View File

@@ -119,7 +119,7 @@ nn::GeneralResult<std::pair<uint32_t, uint32_t>> getNumberOfCacheFilesNeededFrom
<< numberOfCacheFiles.numDataCache << " vs " << nn::kMaxNumberOfCacheFiles
<< ")";
}
return std::make_pair(numberOfCacheFiles.numDataCache, numberOfCacheFiles.numModelCache);
return std::make_pair(numberOfCacheFiles.numModelCache, numberOfCacheFiles.numDataCache);
}
} // namespace

View File

@@ -58,7 +58,7 @@ const std::string kInvalidName = "";
const std::shared_ptr<BnDevice> kInvalidDevice;
constexpr PerformanceInfo kNoPerformanceInfo = {.execTime = std::numeric_limits<float>::max(),
.powerUsage = std::numeric_limits<float>::max()};
constexpr NumberOfCacheFiles kNumberOfCacheFiles = {.numModelCache = nn::kMaxNumberOfCacheFiles,
constexpr NumberOfCacheFiles kNumberOfCacheFiles = {.numModelCache = nn::kMaxNumberOfCacheFiles - 1,
.numDataCache = nn::kMaxNumberOfCacheFiles};
constexpr auto makeStatusOk = [] { return ndk::ScopedAStatus::ok(); };
@@ -300,6 +300,21 @@ TEST(DeviceTest, getSupportedExtensionsDeadObject) {
EXPECT_EQ(result.error().code, nn::ErrorStatus::DEAD_OBJECT);
}
TEST(DeviceTest, getNumberOfCacheFilesNeeded) {
// setup call
const auto mockDevice = createMockDevice();
EXPECT_CALL(*mockDevice, getNumberOfCacheFilesNeeded(_)).Times(1);
// run test
const auto result = Device::create(kName, mockDevice);
// verify result
ASSERT_TRUE(result.has_value());
constexpr auto kNumberOfCacheFilesPair = std::make_pair<uint32_t, uint32_t>(
kNumberOfCacheFiles.numModelCache, kNumberOfCacheFiles.numDataCache);
EXPECT_EQ(result.value()->getNumberOfCacheFilesNeeded(), kNumberOfCacheFilesPair);
}
TEST(DeviceTest, getNumberOfCacheFilesNeededError) {
// setup call
const auto mockDevice = createMockDevice();

View File

@@ -1251,8 +1251,20 @@ TEST_P(RadioHidlTest_v1_5, sendCdmaSmsExpectMore) {
* Test IRadio.getBarringInfo() for the response returned.
*/
TEST_P(RadioHidlTest_v1_5, getBarringInfo) {
// If the previous setRadioPower_1_5_emergencyCall_cancelled test has just finished.
// Due to radio restarting, modem may need a little more time to acquire network service
// and barring infos. If voice status is in-service, waiting 3s to get barring infos ready.
// Or waiting 10s if voice status is not in-service.
serial = GetRandomSerialNumber();
radio_v1_5->getVoiceRegistrationState_1_5(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
if (isVoiceInService(radioRsp_v1_5->voiceRegResp.regState)) {
sleep(BARRING_INFO_MAX_WAIT_TIME_SECONDS);
} else {
sleep(VOICE_SERVICE_MAX_WAIT_TIME_SECONDS);
}
serial = GetRandomSerialNumber();
Return<void> res = radio_v1_5->getBarringInfo(serial);
EXPECT_EQ(std::cv_status::no_timeout, wait());
EXPECT_EQ(RadioResponseType::SOLICITED, radioRsp_v1_5->rspInfo.type);

View File

@@ -51,6 +51,8 @@ using ::android::hardware::Void;
#define TIMEOUT_PERIOD 75
#define MODEM_EMERGENCY_CALL_ESTABLISH_TIME 3
#define MODEM_EMERGENCY_CALL_DISCONNECT_TIME 3
#define VOICE_SERVICE_MAX_WAIT_TIME_SECONDS 10
#define BARRING_INFO_MAX_WAIT_TIME_SECONDS 3
#define RADIO_SERVICE_NAME "slot1"
@@ -69,6 +71,7 @@ class RadioResponse_v1_5 : public ::android::hardware::radio::V1_5::IRadioRespon
// Call
hidl_vec<::android::hardware::radio::V1_2::Call> currentCalls;
::android::hardware::radio::V1_2::VoiceRegStateResult voiceRegResp;
// Modem
bool isModemEnabled;

View File

@@ -763,8 +763,9 @@ Return<void> RadioResponse_v1_5::getCellInfoListResponse_1_2(
Return<void> RadioResponse_v1_5::getVoiceRegistrationStateResponse_1_2(
const RadioResponseInfo& info,
const ::android::hardware::radio::V1_2::VoiceRegStateResult& /*voiceRegResponse*/) {
const ::android::hardware::radio::V1_2::VoiceRegStateResult& voiceRegResponse) {
rspInfo = info;
voiceRegResp = voiceRegResponse;
parent_v1_5.notify(info.serial);
return Void();
}
@@ -989,8 +990,9 @@ Return<void> RadioResponse_v1_5::getBarringInfoResponse(
Return<void> RadioResponse_v1_5::getVoiceRegistrationStateResponse_1_5(
const RadioResponseInfo& info,
const ::android::hardware::radio::V1_5::RegStateResult& /*regResponse*/) {
const ::android::hardware::radio::V1_5::RegStateResult& regResponse) {
rspInfo = info;
voiceRegResp.regState = regResponse.regState;
parent_v1_5.notify(info.serial);
return Void();
}

View File

@@ -44,6 +44,12 @@ parcelable DeviceInfo {
* ? "vendor_patch_level" : uint, // YYYYMMDD
* "version" : 1, // The CDDL schema version.
* "security_level" : "tee" / "strongbox"
* "att_id_state": "locked" / "open", // Attestation IDs State. If "locked", this
* // indicates a device's attestable IDs are
* // factory-locked and immutable. If "open",
* // this indicates the device is still in a
* // provisionable state and the attestable IDs
* // are not yet frozen.
* }
*/
byte[] deviceInfo;

View File

@@ -277,6 +277,10 @@ interface IKeyMintDevice {
* must return ErrorCode::INVALID_ARGUMENT. The values 3 and 65537 must be supported. It is
* recommended to support all prime values up to 2^64.
*
* o Tag::CERTIFICATE_NOT_BEFORE and Tag::CERTIFICATE_NOT_AFTER specify the valid date range for
* the returned X.509 certificate holding the public key. If omitted, generateKey must return
* ErrorCode::MISSING_NOT_BEFORE or ErrorCode::MISSING_NOT_AFTER.
*
* The following parameters are not necessary to generate a usable RSA key, but generateKey must
* not return an error if they are omitted:
*
@@ -297,6 +301,10 @@ interface IKeyMintDevice {
* Tag::EC_CURVE must be provided to generate an ECDSA key. If it is not provided, generateKey
* must return ErrorCode::UNSUPPORTED_KEY_SIZE. TEE IKeyMintDevice implementations must support
* all curves. StrongBox implementations must support P_256.
* Tag::CERTIFICATE_NOT_BEFORE and Tag::CERTIFICATE_NOT_AFTER must be provided to specify the
* valid date range for the returned X.509 certificate holding the public key. If omitted,
* generateKey must return ErrorCode::MISSING_NOT_BEFORE or ErrorCode::MISSING_NOT_AFTER.
*
* == AES Keys ==
*
@@ -805,9 +813,10 @@ interface IKeyMintDevice {
byte[] convertStorageKeyToEphemeral(in byte[] storageKeyBlob);
/**
* Returns parameters associated with the provided key. This should match the
* KeyCharacteristics present in the KeyCreationResult returned by generateKey(),
* importKey(), or importWrappedKey().
* Returns KeyMint-enforced parameters associated with the provided key. The returned tags are
* a subset of KeyCharacteristics found in the KeyCreationResult returned by generateKey(),
* importKey(), or importWrappedKey(). The returned value is a subset, as it does not include
* any Keystore-enforced parameters.
*
* @param keyBlob The opaque descriptor returned by generateKey, importKey or importWrappedKey.
*

View File

@@ -158,20 +158,7 @@ parcelable ProtectedData {
* payload: bstr .cbor BccPayload
* ]
*
* VerifiedDeviceInfo = {
* ? "brand" : tstr,
* ? "manufacturer" : tstr,
* ? "product" : tstr,
* ? "model" : tstr,
* ? "board" : tstr,
* ? "device" : tstr,
* ? "vb_state" : "green" / "yellow" / "orange",
* ? "bootloader_state" : "locked" / "unlocked",
* ? "os_version" : tstr,
* ? "system_patch_level" : uint, // YYYYMMDD
* ? "boot_patch_level" : uint, // YYYYMMDD
* ? "vendor_patch_level" : uint, // YYYYMMDD
* }
* VerifiedDeviceInfo = DeviceInfo // See DeviceInfo.aidl
*
* PubKeyX25519 = { // COSE_Key
* 1 : 1, // Key type : Octet Key Pair

View File

@@ -18,10 +18,6 @@ package android.hardware.security.keymint;
import android.hardware.security.keymint.TagType;
// TODO(seleneh) : note aidl currently does not support double nested enum definitions such as
// ROOT_OF_TRUST = TagType:BYTES | 704. So we are forced to write definitions as
// ROOT_OF_TRUST = (9 << 28) for now. Will need to flip this back later when aidl support is added.
/**
* Tag specifies various kinds of tags that can be set in KeyParameter to identify what kind of
* data are stored in KeyParameter.
@@ -33,7 +29,7 @@ enum Tag {
/**
* Tag::INVALID should never be set. It means you hit an error.
*/
INVALID = (0 << 28) | 0,
INVALID = 0,
/**
* Tag::PURPOSE specifies the set of purposes for which the key may be used. Possible values
@@ -47,7 +43,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
PURPOSE = (2 << 28) /* TagType:ENUM_REP */ | 1,
PURPOSE = TagType.ENUM_REP | 1,
/**
* Tag::ALGORITHM specifies the cryptographic algorithm with which the key is used. This tag
@@ -56,7 +52,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
ALGORITHM = (1 << 28) /* TagType:ENUM */ | 2,
ALGORITHM = TagType.ENUM | 2,
/**
* Tag::KEY_SIZE specifies the size, in bits, of the key, measuring in the normal way for the
@@ -68,7 +64,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
KEY_SIZE = (3 << 28) /* TagType:UINT */ | 3,
KEY_SIZE = TagType.UINT | 3,
/**
* Tag::BLOCK_MODE specifies the block cipher mode(s) with which the key may be used. This tag
@@ -81,7 +77,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
BLOCK_MODE = (2 << 28) /* TagType:ENUM_REP */ | 4,
BLOCK_MODE = TagType.ENUM_REP | 4,
/**
* Tag::DIGEST specifies the digest algorithms that may be used with the key to perform signing
@@ -95,7 +91,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
DIGEST = (2 << 28) /* TagType:ENUM_REP */ | 5,
DIGEST = TagType.ENUM_REP | 5,
/**
* Tag::PADDING specifies the padding modes that may be used with the key. This tag is relevant
@@ -123,7 +119,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
PADDING = (2 << 28) /* TagType:ENUM_REP */ | 6,
PADDING = TagType.ENUM_REP | 6,
/**
* Tag::CALLER_NONCE specifies that the caller can provide a nonce for nonce-requiring
@@ -136,7 +132,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
CALLER_NONCE = (7 << 28) /* TagType:BOOL */ | 7,
CALLER_NONCE = TagType.BOOL | 7,
/**
* Tag::MIN_MAC_LENGTH specifies the minimum length of MAC that can be requested or verified
@@ -149,7 +145,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
MIN_MAC_LENGTH = (3 << 28) /* TagType:UINT */ | 8,
MIN_MAC_LENGTH = TagType.UINT | 8,
// Tag 9 reserved
@@ -159,7 +155,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
EC_CURVE = (1 << 28) /* TagType:ENUM */ | 10,
EC_CURVE = TagType.ENUM | 10,
/**
* Tag::RSA_PUBLIC_EXPONENT specifies the value of the public exponent for an RSA key pair.
@@ -173,7 +169,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
RSA_PUBLIC_EXPONENT = (5 << 28) /* TagType:ULONG */ | 200,
RSA_PUBLIC_EXPONENT = TagType.ULONG | 200,
// Tag 201 reserved
@@ -184,7 +180,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
INCLUDE_UNIQUE_ID = (7 << 28) /* TagType:BOOL */ | 202,
INCLUDE_UNIQUE_ID = TagType.BOOL | 202,
/**
* Tag::RSA_OAEP_MGF_DIGEST specifies the MGF1 digest algorithms that may be used with RSA
@@ -197,7 +193,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
RSA_OAEP_MGF_DIGEST = (2 << 28) /* TagType:ENUM_REP */ | 203,
RSA_OAEP_MGF_DIGEST = TagType.ENUM_REP | 203,
// Tag 301 reserved
@@ -209,7 +205,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
BOOTLOADER_ONLY = (7 << 28) /* TagType:BOOL */ | 302,
BOOTLOADER_ONLY = TagType.BOOL | 302,
/**
* Tag::ROLLBACK_RESISTANCE specifies that the key has rollback resistance, meaning that when
@@ -224,10 +220,10 @@ enum Tag {
*
* Must be hardware-enforced.
*/
ROLLBACK_RESISTANCE = (7 << 28) /* TagType:BOOL */ | 303,
ROLLBACK_RESISTANCE = TagType.BOOL | 303,
// Reserved for future use.
HARDWARE_TYPE = (1 << 28) /* TagType:ENUM */ | 304,
HARDWARE_TYPE = TagType.ENUM | 304,
/**
* Keys tagged with EARLY_BOOT_ONLY may only be used during early boot, until
@@ -236,7 +232,7 @@ enum Tag {
* provided to IKeyMintDevice::importKey, the import must fail with
* ErrorCode::EARLY_BOOT_ENDED.
*/
EARLY_BOOT_ONLY = (7 << 28) /* TagType:BOOL */ | 305,
EARLY_BOOT_ONLY = TagType.BOOL | 305,
/**
* Tag::ACTIVE_DATETIME specifies the date and time at which the key becomes active, in
@@ -245,7 +241,7 @@ enum Tag {
*
* Need not be hardware-enforced.
*/
ACTIVE_DATETIME = (6 << 28) /* TagType:DATE */ | 400,
ACTIVE_DATETIME = TagType.DATE | 400,
/**
* Tag::ORIGINATION_EXPIRE_DATETIME specifies the date and time at which the key expires for
@@ -257,7 +253,7 @@ enum Tag {
*
* Need not be hardware-enforced.
*/
ORIGINATION_EXPIRE_DATETIME = (6 << 28) /* TagType:DATE */ | 401,
ORIGINATION_EXPIRE_DATETIME = TagType.DATE | 401,
/**
* Tag::USAGE_EXPIRE_DATETIME specifies the date and time at which the key expires for
@@ -269,7 +265,7 @@ enum Tag {
*
* Need not be hardware-enforced.
*/
USAGE_EXPIRE_DATETIME = (6 << 28) /* TagType:DATE */ | 402,
USAGE_EXPIRE_DATETIME = TagType.DATE | 402,
/**
* TODO(seleneh) this tag need to be deleted.
@@ -293,8 +289,10 @@ enum Tag {
* fails because the table is full, KeyMint returns ErrorCode::TOO_MANY_OPERATIONS.
*
* Must be hardware-enforced.
*
* TODO(b/191738660): Remove in KeyMint V2. Currently only used for FDE.
*/
MIN_SECONDS_BETWEEN_OPS = (3 << 28) /* TagType:UINT */ | 403,
MIN_SECONDS_BETWEEN_OPS = TagType.UINT | 403,
/**
* Tag::MAX_USES_PER_BOOT specifies the maximum number of times that a key may be used between
@@ -314,7 +312,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
MAX_USES_PER_BOOT = (3 << 28) /* TagType:UINT */ | 404,
MAX_USES_PER_BOOT = TagType.UINT | 404,
/**
* Tag::USAGE_COUNT_LIMIT specifies the number of times that a key may be used. This can be
@@ -343,14 +341,14 @@ enum Tag {
* record. This tag must have the same SecurityLevel as the tag that is added to the key
* characteristics.
*/
USAGE_COUNT_LIMIT = (3 << 28) | 405, /* TagType:UINT */
USAGE_COUNT_LIMIT = TagType.UINT | 405,
/**
* Tag::USER_ID specifies the ID of the Android user that is permitted to use the key.
*
* Must not be hardware-enforced.
*/
USER_ID = (3 << 28) /* TagType:UINT */ | 501,
USER_ID = TagType.UINT | 501,
/**
* Tag::USER_SECURE_ID specifies that a key may only be used under a particular secure user
@@ -383,7 +381,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
USER_SECURE_ID = (10 << 28) /* TagType:ULONG_REP */ | 502,
USER_SECURE_ID = TagType.ULONG_REP | 502,
/**
* Tag::NO_AUTH_REQUIRED specifies that no authentication is required to use this key. This tag
@@ -391,7 +389,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
NO_AUTH_REQUIRED = (7 << 28) /* TagType:BOOL */ | 503,
NO_AUTH_REQUIRED = TagType.BOOL | 503,
/**
* Tag::USER_AUTH_TYPE specifies the types of user authenticators that may be used to authorize
@@ -410,7 +408,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
USER_AUTH_TYPE = (1 << 28) /* TagType:ENUM */ | 504,
USER_AUTH_TYPE = TagType.ENUM | 504,
/**
* Tag::AUTH_TIMEOUT specifies the time in seconds for which the key is authorized for use,
@@ -424,7 +422,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
AUTH_TIMEOUT = (3 << 28) /* TagType:UINT */ | 505,
AUTH_TIMEOUT = TagType.UINT | 505,
/**
* Tag::ALLOW_WHILE_ON_BODY specifies that the key may be used after authentication timeout if
@@ -432,7 +430,7 @@ enum Tag {
*
* Cannot be hardware-enforced.
*/
ALLOW_WHILE_ON_BODY = (7 << 28) /* TagType:BOOL */ | 506,
ALLOW_WHILE_ON_BODY = TagType.BOOL | 506,
/**
* TRUSTED_USER_PRESENCE_REQUIRED is an optional feature that specifies that this key must be
@@ -479,29 +477,31 @@ enum Tag {
*
* Must be hardware-enforced.
*/
TRUSTED_USER_PRESENCE_REQUIRED = (7 << 28) /* TagType:BOOL */ | 507,
TRUSTED_USER_PRESENCE_REQUIRED = TagType.BOOL | 507,
/**
* Tag::TRUSTED_CONFIRMATION_REQUIRED is only applicable to keys with KeyPurpose SIGN, and
* specifies that this key must not be usable unless the user provides confirmation of the data
* to be signed. Confirmation is proven to keyMint via an approval token. See
* CONFIRMATION_TOKEN, as well as the ConfirmationUI HAL.
* specifies that this key must not be usable unless the user provides confirmation of the data
* to be signed. Confirmation is proven to keyMint via an approval token. See the authToken
* parameter of begin(), as well as the ConfirmationUI HAL.
*
* If an attempt to use a key with this tag does not have a cryptographically valid
* CONFIRMATION_TOKEN provided to finish() or if the data provided to update()/finish() does not
* token provided to finish() or if the data provided to update()/finish() does not
* match the data described in the token, keyMint must return NO_USER_CONFIRMATION.
*
* Must be hardware-enforced.
*/
TRUSTED_CONFIRMATION_REQUIRED = (7 << 28) /* TagType:BOOL */ | 508,
TRUSTED_CONFIRMATION_REQUIRED = TagType.BOOL | 508,
/**
* Tag::UNLOCKED_DEVICE_REQUIRED specifies that the key may only be used when the device is
* unlocked.
* unlocked, as reported to KeyMint via authToken operation parameter and the
* IKeyMintDevice::deviceLocked() method
*
* Must be software-enforced.
* Must be hardware-enforced (but is also keystore-enforced on a per-user basis: see the
* deviceLocked() documentation).
*/
UNLOCKED_DEVICE_REQUIRED = (7 << 28) /* TagType:BOOL */ | 509,
UNLOCKED_DEVICE_REQUIRED = TagType.BOOL | 509,
/**
* Tag::APPLICATION_ID. When provided to generateKey or importKey, this tag specifies data
@@ -517,7 +517,7 @@ enum Tag {
*
* Must never appear in KeyCharacteristics.
*/
APPLICATION_ID = (9 << 28) /* TagType:BYTES */ | 601,
APPLICATION_ID = TagType.BYTES | 601,
/*
* Semantically unenforceable tags, either because they have no specific meaning or because
@@ -538,7 +538,7 @@ enum Tag {
*
* Must never appear in KeyCharacteristics.
*/
APPLICATION_DATA = (9 << 28) /* TagType:BYTES */ | 700,
APPLICATION_DATA = TagType.BYTES | 700,
/**
* Tag::CREATION_DATETIME specifies the date and time the key was created, in milliseconds since
@@ -546,7 +546,7 @@ enum Tag {
*
* Must be in the software-enforced list, if provided.
*/
CREATION_DATETIME = (6 << 28) /* TagType:DATE */ | 701,
CREATION_DATETIME = TagType.DATE | 701,
/**
* Tag::ORIGIN specifies where the key was created, if known. This tag must not be specified
@@ -555,7 +555,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
ORIGIN = (1 << 28) /* TagType:ENUM */ | 702,
ORIGIN = TagType.ENUM | 702,
// 703 is unused.
@@ -567,7 +567,7 @@ enum Tag {
*
* Must never appear in KeyCharacteristics.
*/
ROOT_OF_TRUST = (9 << 28) /* TagType:BYTES */ | 704,
ROOT_OF_TRUST = TagType.BYTES | 704,
/**
* Tag::OS_VERSION specifies the system OS version with which the key may be used. This tag is
@@ -590,7 +590,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
OS_VERSION = (3 << 28) /* TagType:UINT */ | 705,
OS_VERSION = TagType.UINT | 705,
/**
* Tag::OS_PATCHLEVEL specifies the system security patch level with which the key may be used.
@@ -611,7 +611,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
OS_PATCHLEVEL = (3 << 28) /* TagType:UINT */ | 706,
OS_PATCHLEVEL = TagType.UINT | 706,
/**
* Tag::UNIQUE_ID specifies a unique, time-based identifier. This tag is never provided to or
@@ -646,7 +646,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
UNIQUE_ID = (9 << 28) /* TagType:BYTES */ | 707,
UNIQUE_ID = TagType.BYTES | 707,
/**
* Tag::ATTESTATION_CHALLENGE is used to deliver a "challenge" value to the attested key
@@ -655,7 +655,7 @@ enum Tag {
*
* Must never appear in KeyCharacteristics.
*/
ATTESTATION_CHALLENGE = (9 << 28) /* TagType:BYTES */ | 708,
ATTESTATION_CHALLENGE = TagType.BYTES | 708,
/**
* Tag::ATTESTATION_APPLICATION_ID identifies the set of applications which may use a key, used
@@ -681,7 +681,7 @@ enum Tag {
*
* Cannot be hardware-enforced.
*/
ATTESTATION_APPLICATION_ID = (9 << 28) /* TagType:BYTES */ | 709,
ATTESTATION_APPLICATION_ID = TagType.BYTES | 709,
/**
* Tag::ATTESTATION_ID_BRAND provides the device's brand name, as returned by Build.BRAND in
@@ -694,7 +694,7 @@ enum Tag {
*
* Must never appear in KeyCharacteristics.
*/
ATTESTATION_ID_BRAND = (9 << 28) /* TagType:BYTES */ | 710,
ATTESTATION_ID_BRAND = TagType.BYTES | 710,
/**
* Tag::ATTESTATION_ID_DEVICE provides the device's device name, as returned by Build.DEVICE in
@@ -707,7 +707,7 @@ enum Tag {
*
* Must never appear in KeyCharacteristics.
*/
ATTESTATION_ID_DEVICE = (9 << 28) /* TagType:BYTES */ | 711,
ATTESTATION_ID_DEVICE = TagType.BYTES | 711,
/**
* Tag::ATTESTATION_ID_PRODUCT provides the device's product name, as returned by Build.PRODUCT
@@ -720,7 +720,7 @@ enum Tag {
*
* Must never appear in KeyCharacteristics.
*/
ATTESTATION_ID_PRODUCT = (9 << 28) /* TagType:BYTES */ | 712,
ATTESTATION_ID_PRODUCT = TagType.BYTES | 712,
/**
* Tag::ATTESTATION_ID_SERIAL the device's serial number. This field must be set only when
@@ -732,7 +732,7 @@ enum Tag {
*
* Must never appear in KeyCharacteristics.
*/
ATTESTATION_ID_SERIAL = (9 << 28) /* TagType:BYTES */ | 713,
ATTESTATION_ID_SERIAL = TagType.BYTES | 713,
/**
* Tag::ATTESTATION_ID_IMEI provides the IMEIs for all radios on the device to attested key
@@ -745,7 +745,7 @@ enum Tag {
*
* Must never appear in KeyCharacteristics.
*/
ATTESTATION_ID_IMEI = (9 << 28) /* TagType:BYTES */ | 714,
ATTESTATION_ID_IMEI = TagType.BYTES | 714,
/**
* Tag::ATTESTATION_ID_MEID provides the MEIDs for all radios on the device to attested key
@@ -758,7 +758,7 @@ enum Tag {
*
* Must never appear in KeyCharacteristics.
*/
ATTESTATION_ID_MEID = (9 << 28) /* TagType:BYTES */ | 715,
ATTESTATION_ID_MEID = TagType.BYTES | 715,
/**
* Tag::ATTESTATION_ID_MANUFACTURER provides the device's manufacturer name, as returned by
@@ -771,7 +771,7 @@ enum Tag {
*
* Must never appear in KeyCharacteristics.
*/
ATTESTATION_ID_MANUFACTURER = (9 << 28) /* TagType:BYTES */ | 716,
ATTESTATION_ID_MANUFACTURER = TagType.BYTES | 716,
/**
* Tag::ATTESTATION_ID_MODEL provides the device's model name, as returned by Build.MODEL in
@@ -784,7 +784,7 @@ enum Tag {
*
* Must never appear in KeyCharacteristics.
*/
ATTESTATION_ID_MODEL = (9 << 28) /* TagType:BYTES */ | 717,
ATTESTATION_ID_MODEL = TagType.BYTES | 717,
/**
* Tag::VENDOR_PATCHLEVEL specifies the vendor image security patch level with which the key may
@@ -806,7 +806,7 @@ enum Tag {
*
* Must be hardware-enforced.
*/
VENDOR_PATCHLEVEL = (3 << 28) /* TagType:UINT */ | 718,
VENDOR_PATCHLEVEL = TagType.UINT | 718,
/**
* Tag::BOOT_PATCHLEVEL specifies the boot image (kernel) security patch level with which the
@@ -826,16 +826,26 @@ enum Tag {
*
* Must be hardware-enforced.
*/
BOOT_PATCHLEVEL = (3 << 28) /* TagType:UINT */ | 719,
BOOT_PATCHLEVEL = TagType.UINT | 719,
/**
* DEVICE_UNIQUE_ATTESTATION is an argument to IKeyMintDevice::attested key generation/import
* operations. It indicates that attestation using a device-unique key is requested, rather
* than a batch key. When a device-unique key is used, the returned chain should contain two
* certificates:
* than a batch key. When a device-unique key is used, the returned chain contains two or
* three certificates.
*
* In case the chain contains two certificates, they should be:
* * The attestation certificate, containing the attestation extension, as described in
KeyCreationResult.aidl.
* KeyCreationResult.aidl.
* * A self-signed root certificate, signed by the device-unique key.
*
* In case the chain contains three certificates, they should be:
* * The attestation certificate, containing the attestation extension, as described in
* KeyCreationResult.aidl, signed by the device-unique key.
* * An intermediate certificate, containing the public portion of the device-unique key.
* * A self-signed root certificate, signed by a dedicated key, certifying the
* intermediate.
*
* No additional chained certificates are provided. Only SecurityLevel::STRONGBOX
* IKeyMintDevices may support device-unique attestations. SecurityLevel::TRUSTED_ENVIRONMENT
* IKeyMintDevices must return ErrorCode::INVALID_ARGUMENT if they receive
@@ -852,7 +862,7 @@ enum Tag {
* IKeyMintDevice implementations that support device-unique attestation MUST add the
* DEVICE_UNIQUE_ATTESTATION tag to device-unique attestations.
*/
DEVICE_UNIQUE_ATTESTATION = (7 << 28) /* TagType:BOOL */ | 720,
DEVICE_UNIQUE_ATTESTATION = TagType.BOOL | 720,
/**
* IDENTITY_CREDENTIAL_KEY is never used by IKeyMintDevice, is not a valid argument to key
@@ -860,7 +870,7 @@ enum Tag {
* attestation. It is used in attestations produced by the IIdentityCredential HAL when that
* HAL attests to Credential Keys. IIdentityCredential produces KeyMint-style attestations.
*/
IDENTITY_CREDENTIAL_KEY = (7 << 28) /* TagType:BOOL */ | 721,
IDENTITY_CREDENTIAL_KEY = TagType.BOOL | 721,
/**
* To prevent keys from being compromised if an attacker acquires read access to system / kernel
@@ -870,19 +880,21 @@ enum Tag {
*
* STORAGE_KEY is used to denote that a key generated or imported is a key used for storage
* encryption. Keys of this type can either be generated or imported or secure imported using
* keyMint. exportKey() can be used to re-wrap storage key with a per-boot ephemeral key
* wrapped key once the key characteristics are enforced.
* keyMint. The convertStorageKeyToEphemeral() method of IKeyMintDevice can be used to re-wrap
* storage key with a per-boot ephemeral key wrapped key once the key characteristics are
* enforced.
*
* Keys with this tag cannot be used for any operation within keyMint.
* ErrorCode::INVALID_OPERATION is returned when a key with Tag::STORAGE_KEY is provided to
* begin().
*/
STORAGE_KEY = (7 << 28) /* TagType:BOOL */ | 722,
STORAGE_KEY = TagType.BOOL | 722,
/**
* TODO: Delete when keystore1 is deleted.
* OBSOLETE: Do not use. See IKeyMintOperation.updateAad instead.
* TODO(b/191738660): Remove in KeyMint v2.
*/
ASSOCIATED_DATA = (9 << 28) /* TagType:BYTES */ | 1000,
ASSOCIATED_DATA = TagType.BYTES | 1000,
/**
* Tag::NONCE is used to provide or return a nonce or Initialization Vector (IV) for AES-GCM,
@@ -897,7 +909,7 @@ enum Tag {
*
* Must never appear in KeyCharacteristics.
*/
NONCE = (9 << 28) /* TagType:BYTES */ | 1001,
NONCE = TagType.BYTES | 1001,
/**
* Tag::MAC_LENGTH provides the requested length of a MAC or GCM authentication tag, in bits.
@@ -908,7 +920,7 @@ enum Tag {
*
* Must never appear in KeyCharacteristics.
*/
MAC_LENGTH = (3 << 28) /* TagType:UINT */ | 1003,
MAC_LENGTH = TagType.UINT | 1003,
/**
* Tag::RESET_SINCE_ID_ROTATION specifies whether the device has been factory reset since the
@@ -916,16 +928,15 @@ enum Tag {
*
* Must never appear in KeyCharacteristics.
*/
RESET_SINCE_ID_ROTATION = (7 << 28) /* TagType:BOOL */ | 1004,
RESET_SINCE_ID_ROTATION = TagType.BOOL | 1004,
/**
* Tag::CONFIRMATION_TOKEN is used to deliver a cryptographic token proving that the user
* confirmed a signing request. The content is a full-length HMAC-SHA256 value. See the
* ConfirmationUI HAL for details of token computation.
* OBSOLETE: Do not use. See the authToken parameter for IKeyMintDevice::begin and for
* IKeyMintOperation methods instead.
*
* Must never appear in KeyCharacteristics.
* TODO(b/191738660): Delete when keystore1 is deleted.
*/
CONFIRMATION_TOKEN = (9 << 28) /* TagType:BYTES */ | 1005,
CONFIRMATION_TOKEN = TagType.BYTES | 1005,
/**
* Tag::CERTIFICATE_SERIAL specifies the serial number to be assigned to the attestation
@@ -933,7 +944,7 @@ enum Tag {
* keyMint in the attestation parameters during generateKey() and importKey(). If not provided,
* the serial shall default to 1.
*/
CERTIFICATE_SERIAL = (8 << 28) /* TagType:BIGNUM */ | 1006,
CERTIFICATE_SERIAL = TagType.BIGNUM | 1006,
/**
* Tag::CERTIFICATE_SUBJECT the certificate subject. The value is a DER encoded X509 NAME.
@@ -941,7 +952,7 @@ enum Tag {
* during generateKey and importKey. If not provided the subject name shall default to
* CN="Android Keystore Key".
*/
CERTIFICATE_SUBJECT = (9 << 28) /* TagType:BYTES */ | 1007,
CERTIFICATE_SUBJECT = TagType.BYTES | 1007,
/**
* Tag::CERTIFICATE_NOT_BEFORE the beginning of the validity of the certificate in UNIX epoch
@@ -949,7 +960,7 @@ enum Tag {
* certificates. ErrorCode::MISSING_NOT_BEFORE must be returned if this tag is not provided if
* this tag is not provided to generateKey or importKey.
*/
CERTIFICATE_NOT_BEFORE = (6 << 28) /* TagType:DATE */ | 1008,
CERTIFICATE_NOT_BEFORE = TagType.DATE | 1008,
/**
* Tag::CERTIFICATE_NOT_AFTER the end of the validity of the certificate in UNIX epoch time in
@@ -957,7 +968,7 @@ enum Tag {
* ErrorCode::MISSING_NOT_AFTER must be returned if this tag is not provided to generateKey or
* importKey.
*/
CERTIFICATE_NOT_AFTER = (6 << 28) /* TagType:DATE */ | 1009,
CERTIFICATE_NOT_AFTER = TagType.DATE | 1009,
/**
* Tag::MAX_BOOT_LEVEL specifies a maximum boot level at which a key should function.
@@ -968,5 +979,5 @@ enum Tag {
*
* Cannot be hardware enforced in this version.
*/
MAX_BOOT_LEVEL = (3 << 28) /* TagType:UINT */ | 1010,
MAX_BOOT_LEVEL = TagType.UINT | 1010,
}

View File

@@ -23,16 +23,11 @@ package {
default_applicable_licenses: ["hardware_interfaces_license"],
}
cc_test {
name: "VtsAidlKeyMintTargetTest",
cc_defaults {
name: "keymint_vts_defaults",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
],
srcs: [
"AttestKeyTest.cpp",
"DeviceUniqueAttestationTest.cpp",
"KeyMintTest.cpp",
"VtsHalTargetTestDefaults",
],
shared_libs: [
"libbinder_ndk",
@@ -43,9 +38,24 @@ cc_test {
"android.hardware.security.secureclock-V1-ndk_platform",
"libcppbor_external",
"libcppcose_rkp",
"libjsoncpp",
"libkeymint",
"libkeymint_remote_prov_support",
"libkeymint_support",
],
}
cc_test {
name: "VtsAidlKeyMintTargetTest",
defaults: [
"keymint_vts_defaults",
],
srcs: [
"AttestKeyTest.cpp",
"DeviceUniqueAttestationTest.cpp",
"KeyMintTest.cpp",
],
static_libs: [
"libkeymint_vts_test_utils",
],
test_suites: [
@@ -57,8 +67,7 @@ cc_test {
cc_test_library {
name: "libkeymint_vts_test_utils",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
"keymint_vts_defaults",
],
srcs: [
"KeyMintAidlTestBase.cpp",
@@ -66,48 +75,26 @@ cc_test_library {
export_include_dirs: [
".",
],
shared_libs: [
"libbinder_ndk",
"libcrypto",
],
static_libs: [
"android.hardware.security.keymint-V1-ndk_platform",
"android.hardware.security.secureclock-V1-ndk_platform",
"libcppbor_external",
"libcppcose_rkp",
"libgmock_ndk",
"libkeymint",
"libkeymint_remote_prov_support",
"libkeymint_support",
],
}
cc_test {
name: "VtsHalRemotelyProvisionedComponentTargetTest",
defaults: [
"VtsHalTargetTestDefaults",
"use_libaidlvintf_gtest_helper_static",
"keymint_vts_defaults",
],
srcs: [
"VtsRemotelyProvisionedComponentTests.cpp",
],
shared_libs: [
"libbinder_ndk",
"libcrypto",
],
static_libs: [
"android.hardware.security.keymint-V1-ndk_platform",
"android.hardware.security.secureclock-V1-ndk_platform",
"libcppbor_external",
"libcppcose_rkp",
"libgmock_ndk",
"libkeymaster_portable",
"libkeymint",
"libkeymint_support",
"libkeymint_remote_prov_support",
"libkeymint_vts_test_utils",
"libpuresoftkeymasterdevice",
],
test_config: "VtsRemotelyProvisionedComponentTests.xml",
test_suites: [
"general-tests",
"vts",

View File

@@ -40,11 +40,16 @@ class DeviceUniqueAttestationTest : public KeyMintAidlTestBase {
AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
// The device-unique attestation chain should contain exactly two certificates:
// The device-unique attestation chain should contain exactly three certificates:
// * The leaf with the attestation extension.
// * A self-signed root, signed using the device-unique key.
ASSERT_EQ(cert_chain_.size(), 2);
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
// * An intermediate, signing the leaf using the device-unique key.
// * A self-signed root, signed using some authority's key, certifying
// the device-unique key.
const size_t chain_length = cert_chain_.size();
ASSERT_TRUE(chain_length == 2 || chain_length == 3);
// TODO(b/191361618): Once StrongBox implementations use a correctly-issued
// certificate chain, do not skip issuers matching.
EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_, /* strict_issuer_check= */ false));
AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
EXPECT_TRUE(verify_attestation_record("challenge", "foo", sw_enforced, hw_enforced,

View File

@@ -1493,7 +1493,8 @@ AuthorizationSet SwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_
return authList;
}
AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain) {
AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain,
bool strict_issuer_check) {
std::stringstream cert_data;
for (size_t i = 0; i < chain.size(); ++i) {
@@ -1520,7 +1521,7 @@ AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain) {
string cert_issuer = x509NameToStr(X509_get_issuer_name(key_cert.get()));
string signer_subj = x509NameToStr(X509_get_subject_name(signing_cert.get()));
if (cert_issuer != signer_subj) {
if (cert_issuer != signer_subj && strict_issuer_check) {
return AssertionFailure() << "Cert " << i << " has wrong issuer.\n"
<< " Signer subject is " << signer_subj
<< " Issuer subject is " << cert_issuer << endl

View File

@@ -349,7 +349,8 @@ void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey);
AuthorizationSet HwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
AuthorizationSet SwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
::testing::AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain);
::testing::AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain,
bool strict_issuer_check = true);
#define INSTANTIATE_KEYMINT_AIDL_TEST(name) \
INSTANTIATE_TEST_SUITE_P(PerInstance, name, \

View File

@@ -1487,9 +1487,8 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestationTags) {
tag.tag == TAG_ROLLBACK_RESISTANCE) {
continue;
}
if (result == ErrorCode::UNSUPPORTED_TAG &&
(tag.tag == TAG_ALLOW_WHILE_ON_BODY || tag.tag == TAG_TRUSTED_USER_PRESENCE_REQUIRED)) {
// Optional tag not supported by this KeyMint implementation.
if (result == ErrorCode::UNSUPPORTED_TAG && tag.tag == TAG_TRUSTED_USER_PRESENCE_REQUIRED) {
// Tag not required to be supported by all KeyMint implementations.
continue;
}
ASSERT_EQ(result, ErrorCode::OK);
@@ -1501,9 +1500,8 @@ TEST_P(NewKeyGenerationTest, EcdsaAttestationTags) {
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
AuthorizationSet sw_enforced = SwEnforcedAuthorizations(key_characteristics);
if (tag.tag != TAG_ATTESTATION_APPLICATION_ID) {
// Expect to find most of the extra tags in the key characteristics
// of the generated key (but not for ATTESTATION_APPLICATION_ID).
// Some tags are optional, so don't require them to be in the enforcements.
if (tag.tag != TAG_ATTESTATION_APPLICATION_ID && tag.tag != TAG_ALLOW_WHILE_ON_BODY) {
EXPECT_TRUE(hw_enforced.Contains(tag.tag) || sw_enforced.Contains(tag.tag))
<< tag << " not in hw:" << hw_enforced << " nor sw:" << sw_enforced;
}

View File

@@ -29,6 +29,7 @@
#include <openssl/ec_key.h>
#include <openssl/x509.h>
#include <remote_prov/remote_prov_utils.h>
#include <vector>
#include "KeyMintAidlTestBase.h"
@@ -40,6 +41,7 @@ using ::std::vector;
namespace {
#define INSTANTIATE_REM_PROV_AIDL_TEST(name) \
GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(name); \
INSTANTIATE_TEST_SUITE_P( \
PerInstance, name, \
testing::ValuesIn(VtsRemotelyProvisionedComponentTests::build_params()), \
@@ -102,8 +104,8 @@ ErrMsgOr<cppbor::Array> corrupt_sig(const cppbor::Array* coseSign1) {
return std::move(corruptSig);
}
ErrMsgOr<EekChain> corrupt_sig_chain(const EekChain& eek, int which) {
auto [chain, _, parseErr] = cppbor::parse(eek.chain);
ErrMsgOr<bytevec> corrupt_sig_chain(const bytevec& encodedEekChain, int which) {
auto [chain, _, parseErr] = cppbor::parse(encodedEekChain);
if (!chain || !chain->asArray()) {
return "EekChain parse failed";
}
@@ -125,7 +127,7 @@ ErrMsgOr<EekChain> corrupt_sig_chain(const EekChain& eek, int which) {
corruptChain.add(eekChain->get(ii)->clone());
}
}
return EekChain{corruptChain.encode(), eek.last_pubkey, eek.last_privkey};
return corruptChain.encode();
}
string device_suffix(const string& name) {
@@ -271,14 +273,14 @@ TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) {
class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
protected:
CertificateRequestTest() : eekId_(string_to_bytevec("eekid")), challenge_(randomBytes(32)) {
generateEek(3);
generateTestEekChain(3);
}
void generateEek(size_t eekLength) {
void generateTestEekChain(size_t eekLength) {
auto chain = generateEekChain(eekLength, eekId_);
EXPECT_TRUE(chain) << chain.message();
if (chain) eekChain_ = chain.moveValue();
eekLength_ = eekLength;
if (chain) testEekChain_ = chain.moveValue();
testEekLength_ = eekLength;
}
void generateKeys(bool testMode, size_t numKeys) {
@@ -297,7 +299,8 @@ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
}
void checkProtectedData(const DeviceInfo& deviceInfo, const cppbor::Array& keysToSign,
const bytevec& keysToSignMac, const ProtectedData& protectedData) {
const bytevec& keysToSignMac, const ProtectedData& protectedData,
std::vector<BccEntryData>* bccOutput = nullptr) {
auto [parsedProtectedData, _, protDataErrMsg] = cppbor::parse(protectedData.protectedData);
ASSERT_TRUE(parsedProtectedData) << protDataErrMsg;
ASSERT_TRUE(parsedProtectedData->asArray());
@@ -307,8 +310,9 @@ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
ASSERT_TRUE(senderPubkey) << senderPubkey.message();
EXPECT_EQ(senderPubkey->second, eekId_);
auto sessionKey = x25519_HKDF_DeriveKey(eekChain_.last_pubkey, eekChain_.last_privkey,
senderPubkey->first, false /* senderIsA */);
auto sessionKey =
x25519_HKDF_DeriveKey(testEekChain_.last_pubkey, testEekChain_.last_privkey,
senderPubkey->first, false /* senderIsA */);
ASSERT_TRUE(sessionKey) << sessionKey.message();
auto protectedDataPayload =
@@ -354,11 +358,15 @@ class CertificateRequestTest : public VtsRemotelyProvisionedComponentTests {
auto macPayload = verifyAndParseCoseMac0(&coseMac0, *macKey);
ASSERT_TRUE(macPayload) << macPayload.message();
if (bccOutput) {
*bccOutput = std::move(*bccContents);
}
}
bytevec eekId_;
size_t eekLength_;
EekChain eekChain_;
size_t testEekLength_;
EekChain testEekChain_;
bytevec challenge_;
std::vector<MacedPublicKey> keysToSign_;
cppbor::Array cborKeysToSign_;
@@ -372,13 +380,13 @@ TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
bool testMode = true;
for (size_t eekLength : {2, 3, 7}) {
SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
generateEek(eekLength);
generateTestEekChain(eekLength);
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
@@ -387,30 +395,61 @@ TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
}
/**
* Generate an empty certificate request in prod mode. Generation will fail because we don't have a
* valid GEEK.
*
* TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
* able to decrypt.
* Ensure that test mode outputs a unique BCC root key every time we request a
* certificate request. Else, it's possible that the test mode API could be used
* to fingerprint devices. Only the GEEK should be allowed to decrypt the same
* device public key multiple times.
*/
TEST_P(CertificateRequestTest, EmptyRequest_prodMode) {
bool testMode = false;
for (size_t eekLength : {2, 3, 7}) {
SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
generateEek(eekLength);
TEST_P(CertificateRequestTest, NewKeyPerCallInTestMode) {
constexpr bool testMode = true;
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, {} /* keysToSign */, eekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
EXPECT_FALSE(status.isOk());
EXPECT_EQ(status.getServiceSpecificError(),
BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
std::vector<BccEntryData> firstBcc;
checkProtectedData(deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData,
&firstBcc);
status = provisionable_->generateCertificateRequest(
testMode, {} /* keysToSign */, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
std::vector<BccEntryData> secondBcc;
checkProtectedData(deviceInfo, /*keysToSign=*/cppbor::Array(), keysToSignMac, protectedData,
&secondBcc);
// Verify that none of the keys in the first BCC are repeated in the second one.
for (const auto& i : firstBcc) {
for (auto& j : secondBcc) {
ASSERT_THAT(i.pubKey, testing::Not(testing::ElementsAreArray(j.pubKey)))
<< "Found a repeated pubkey in two generateCertificateRequest test mode calls";
}
}
}
/**
* Generate an empty certificate request in prod mode. This test must be run explicitly, and
* is not run by default. Not all devices are GMS devices, and therefore they do not all
* trust the Google EEK root.
*/
TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_prodMode) {
bool testMode = false;
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, {} /* keysToSign */, getProdEekChain(), challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
EXPECT_TRUE(status.isOk());
}
/**
* Generate a non-empty certificate request in test mode. Decrypt, parse and validate the contents.
*/
@@ -420,13 +459,13 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
for (size_t eekLength : {2, 3, 7}) {
SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
generateEek(eekLength);
generateTestEekChain(eekLength);
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
testMode, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo, &protectedData,
&keysToSignMac);
ASSERT_TRUE(status.isOk()) << status.getMessage();
@@ -435,30 +474,21 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
}
/**
* Generate a non-empty certificate request in prod mode. Must fail because we don't have a valid
* GEEK.
*
* TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
* able to decrypt.
* Generate a non-empty certificate request in prod mode. This test must be run explicitly, and
* is not run by default. Not all devices are GMS devices, and therefore they do not all
* trust the Google EEK root.
*/
TEST_P(CertificateRequestTest, NonEmptyRequest_prodMode) {
TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodMode) {
bool testMode = false;
generateKeys(testMode, 4 /* numKeys */);
for (size_t eekLength : {2, 3, 7}) {
SCOPED_TRACE(testing::Message() << "EEK of length " << eekLength);
generateEek(eekLength);
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, keysToSign_, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
&keysToSignMac);
EXPECT_FALSE(status.isOk());
EXPECT_EQ(status.getServiceSpecificError(),
BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
}
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, keysToSign_, getProdEekChain(), challenge_, &deviceInfo, &protectedData,
&keysToSignMac);
EXPECT_TRUE(status.isOk());
}
/**
@@ -473,8 +503,8 @@ TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) {
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
&keysToSignMac);
testMode, {keyWithCorruptMac}, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_FALSE(status.isOk()) << status.getMessage();
EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
}
@@ -483,7 +513,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_testMode) {
* Generate a non-empty certificate request in prod mode, but with the MAC corrupted on the keypair.
*/
TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
bool testMode = true;
bool testMode = false;
generateKeys(testMode, 1 /* numKeys */);
MacedPublicKey keyWithCorruptMac = corrupt_maced_key(keysToSign_[0]).moveValue();
@@ -491,38 +521,35 @@ TEST_P(CertificateRequestTest, NonEmptyRequestCorruptMac_prodMode) {
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, {keyWithCorruptMac}, eekChain_.chain, challenge_, &deviceInfo, &protectedData,
&keysToSignMac);
testMode, {keyWithCorruptMac}, getProdEekChain(), challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_FALSE(status.isOk()) << status.getMessage();
auto rc = status.getServiceSpecificError();
// TODO(drysdale): drop the INVALID_EEK potential error code when a real GEEK is available.
EXPECT_TRUE(rc == BnRemotelyProvisionedComponent::STATUS_INVALID_EEK ||
rc == BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
EXPECT_EQ(status.getServiceSpecificError(), BnRemotelyProvisionedComponent::STATUS_INVALID_MAC);
}
/**
* Generate a non-empty certificate request in prod mode that has a corrupt EEK chain.
* Confirm that the request is rejected.
*
* TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
* implementation is checking signatures.
*/
TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
bool testMode = false;
generateKeys(testMode, 4 /* numKeys */);
for (size_t ii = 0; ii < eekLength_; ii++) {
auto chain = corrupt_sig_chain(eekChain_, ii);
auto prodEekChain = getProdEekChain();
auto [parsedChain, _, parseErr] = cppbor::parse(prodEekChain);
ASSERT_NE(parsedChain, nullptr) << parseErr;
ASSERT_NE(parsedChain->asArray(), nullptr);
for (int ii = 0; ii < parsedChain->asArray()->size(); ++ii) {
auto chain = corrupt_sig_chain(prodEekChain, ii);
ASSERT_TRUE(chain) << chain.message();
EekChain corruptEek = chain.moveValue();
bytevec keysToSignMac;
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
testMode, keysToSign_, corruptEek.chain, challenge_, &deviceInfo, &protectedData,
&keysToSignMac);
auto status = provisionable_->generateCertificateRequest(testMode, keysToSign_, *chain,
challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_FALSE(status.isOk());
ASSERT_EQ(status.getServiceSpecificError(),
BnRemotelyProvisionedComponent::STATUS_INVALID_EEK);
@@ -532,9 +559,6 @@ TEST_P(CertificateRequestTest, NonEmptyCorruptEekRequest_prodMode) {
/**
* Generate a non-empty certificate request in prod mode that has an incomplete EEK chain.
* Confirm that the request is rejected.
*
* TODO(drysdale): Update to use a valid GEEK, so that the test actually confirms that the
* implementation is checking signatures.
*/
TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {
bool testMode = false;
@@ -542,7 +566,7 @@ TEST_P(CertificateRequestTest, NonEmptyIncompleteEekRequest_prodMode) {
// Build an EEK chain that omits the first self-signed cert.
auto truncatedChain = cppbor::Array();
auto [chain, _, parseErr] = cppbor::parse(eekChain_.chain);
auto [chain, _, parseErr] = cppbor::parse(getProdEekChain());
ASSERT_TRUE(chain);
auto eekChain = chain->asArray();
ASSERT_NE(eekChain, nullptr);
@@ -571,7 +595,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
true /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
true /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_FALSE(status.isOk());
ASSERT_EQ(status.getServiceSpecificError(),
@@ -589,7 +613,7 @@ TEST_P(CertificateRequestTest, NonEmptyRequest_testKeyInProdCert) {
DeviceInfo deviceInfo;
ProtectedData protectedData;
auto status = provisionable_->generateCertificateRequest(
false /* testMode */, keysToSign_, eekChain_.chain, challenge_, &deviceInfo,
false /* testMode */, keysToSign_, testEekChain_.chain, challenge_, &deviceInfo,
&protectedData, &keysToSignMac);
ASSERT_FALSE(status.isOk());
ASSERT_EQ(status.getServiceSpecificError(),

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2021 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.
-->
<configuration description="Runs VtsHalRemotelyProvisionedComponentTargetTest.">
<option name="test-suite-tag" value="apct" />
<option name="test-suite-tag" value="apct-native" />
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
<option name="push-file"
key="VtsHalRemotelyProvisionedComponentTargetTest"
value="/data/local/tmp/VtsHalRemotelyProvisionedComponentTargetTest" />
</target_preparer>
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
<option name="module-name" value="VtsHalRemotelyProvisionedComponentTargetTest" />
<option name="native-test-timeout" value="900000"/> <!-- 15 minutes -->
</test>
</configuration>

View File

@@ -57,8 +57,28 @@ cc_library {
"include",
],
shared_libs: [
"libbase",
"libcppbor_external",
"libcppcose_rkp",
"libcrypto",
"libjsoncpp",
],
}
cc_test {
name: "libkeymint_remote_prov_support_test",
srcs: ["remote_prov_utils_test.cpp"],
static_libs: [
"libgmock",
"libgtest_main",
],
shared_libs: [
"libbase",
"libcppbor_external",
"libcppcose_rkp",
"libcrypto",
"libjsoncpp",
"libkeymaster_portable",
"libkeymint_remote_prov_support",
],
}

View File

@@ -27,6 +27,31 @@ using namespace cppcose;
extern bytevec kTestMacKey;
// The Google root key for the Endpoint Encryption Key chain, encoded as COSE_Sign1
inline constexpr uint8_t kCoseEncodedRootCert[] = {
0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x58, 0x2a, 0xa4, 0x01, 0x01, 0x03, 0x27, 0x20, 0x06,
0x21, 0x58, 0x20, 0x99, 0xb9, 0xee, 0xdd, 0x5e, 0xe4, 0x52, 0xf6, 0x85, 0xc6, 0x4c, 0x62,
0xdc, 0x3e, 0x61, 0xab, 0x57, 0x48, 0x7d, 0x75, 0x37, 0x29, 0xad, 0x76, 0x80, 0x32, 0xd2,
0xb3, 0xcb, 0x63, 0x58, 0xd9, 0x58, 0x40, 0x1e, 0x22, 0x08, 0x4b, 0xa4, 0xb7, 0xa4, 0xc8,
0xd7, 0x4e, 0x03, 0x0e, 0xfe, 0xb8, 0xaf, 0x14, 0x4c, 0xa7, 0x3b, 0x6f, 0xa5, 0xcd, 0xdc,
0xda, 0x79, 0xc6, 0x2b, 0x64, 0xfe, 0x99, 0x39, 0xaf, 0x76, 0xe7, 0x80, 0xfa, 0x66, 0x00,
0x85, 0x0d, 0x07, 0x98, 0x2a, 0xac, 0x91, 0x5c, 0xa7, 0x25, 0x14, 0x49, 0x06, 0x34, 0x75,
0xca, 0x8a, 0x27, 0x7a, 0xd9, 0xe3, 0x5a, 0x49, 0xeb, 0x02, 0x03};
// The Google Endpoint Encryption Key certificate, encoded as COSE_Sign1
inline constexpr uint8_t kCoseEncodedGeekCert[] = {
0x84, 0x43, 0xa1, 0x01, 0x27, 0xa0, 0x58, 0x4e, 0xa5, 0x01, 0x01, 0x02, 0x58, 0x20,
0xd0, 0xae, 0xc1, 0x15, 0xca, 0x2a, 0xcf, 0x73, 0xae, 0x6b, 0xcc, 0xcb, 0xd1, 0x96,
0x1d, 0x65, 0xe8, 0xb1, 0xdd, 0xd7, 0x4a, 0x1a, 0x37, 0xb9, 0x43, 0x3a, 0x97, 0xd5,
0x99, 0xdf, 0x98, 0x08, 0x03, 0x38, 0x18, 0x20, 0x04, 0x21, 0x58, 0x20, 0xbe, 0x85,
0xe7, 0x46, 0xc4, 0xa3, 0x42, 0x5a, 0x40, 0xd9, 0x36, 0x3a, 0xa6, 0x15, 0xd0, 0x2c,
0x58, 0x7e, 0x3d, 0xdc, 0x33, 0x02, 0x32, 0xd2, 0xfc, 0x5e, 0x1e, 0x87, 0x25, 0x5f,
0x72, 0x60, 0x58, 0x40, 0x9b, 0xcf, 0x90, 0xe2, 0x2e, 0x4b, 0xab, 0xd1, 0x18, 0xb1,
0x0e, 0x8e, 0x5d, 0x20, 0x27, 0x4b, 0x84, 0x58, 0xfe, 0xfc, 0x32, 0x90, 0x7e, 0x72,
0x05, 0x83, 0xbc, 0xd7, 0x82, 0xbe, 0xfa, 0x64, 0x78, 0x2d, 0x54, 0x10, 0x4b, 0xc0,
0x31, 0xbf, 0x6b, 0xe8, 0x1e, 0x35, 0xe2, 0xf0, 0x2d, 0xce, 0x6c, 0x2f, 0x4f, 0xf2,
0xf5, 0x4f, 0xa5, 0xd4, 0x83, 0xad, 0x96, 0xa2, 0xf1, 0x87, 0x58, 0x04};
/**
* Generates random bytes.
*/
@@ -44,6 +69,11 @@ struct EekChain {
*/
ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId);
/**
* Returns the CBOR-encoded, production Google Endpoint Encryption Key chain.
*/
bytevec getProdEekChain();
struct BccEntryData {
bytevec pubKey;
};
@@ -57,4 +87,26 @@ struct BccEntryData {
*/
ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc);
struct JsonOutput {
static JsonOutput Ok(std::string json) { return {std::move(json), ""}; }
static JsonOutput Error(std::string error) { return {"", std::move(error)}; }
std::string output;
std::string error; // if non-empty, this describes what went wrong
};
/**
* Take a given certificate request and output a JSON blob containing both the
* build fingerprint and certificate request. This data may be serialized, then
* later uploaded to the remote provisioning service. The input csr is not
* validated, only encoded.
*
* Output format:
* {
* "build_fingerprint": <string>
* "csr": <base64 CBOR CSR>
* }
*/
JsonOutput jsonEncodeCsrWithBuild(const cppbor::Array& csr);
} // namespace aidl::android::hardware::security::keymint::remote_prov

View File

@@ -14,11 +14,15 @@
* limitations under the License.
*/
#include <remote_prov/remote_prov_utils.h>
#include <openssl/rand.h>
#include <iterator>
#include <tuple>
#include <android-base/properties.h>
#include <cppbor.h>
#include <json/json.h>
#include <openssl/base64.h>
#include <openssl/rand.h>
#include <remote_prov/remote_prov_utils.h>
namespace aidl::android::hardware::security::keymint::remote_prov {
@@ -31,6 +35,10 @@ bytevec randomBytes(size_t numBytes) {
}
ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId) {
if (length < 2) {
return "EEK chain must contain at least 2 certs.";
}
auto eekChain = cppbor::Array();
bytevec prev_priv_key;
@@ -78,6 +86,18 @@ ErrMsgOr<EekChain> generateEekChain(size_t length, const bytevec& eekId) {
return EekChain{eekChain.encode(), pub_key, priv_key};
}
bytevec getProdEekChain() {
bytevec prodEek;
prodEek.reserve(1 + sizeof(kCoseEncodedRootCert) + sizeof(kCoseEncodedGeekCert));
// In CBOR encoding, 0x82 indicates an array of two items
prodEek.push_back(0x82);
prodEek.insert(prodEek.end(), std::begin(kCoseEncodedRootCert), std::end(kCoseEncodedRootCert));
prodEek.insert(prodEek.end(), std::begin(kCoseEncodedGeekCert), std::end(kCoseEncodedGeekCert));
return prodEek;
}
ErrMsgOr<bytevec> verifyAndParseCoseSign1Cwt(const cppbor::Array* coseSign1,
const bytevec& signingCoseKey, const bytevec& aad) {
if (!coseSign1 || coseSign1->size() != kCoseSign1EntryCount) {
@@ -162,4 +182,36 @@ ErrMsgOr<std::vector<BccEntryData>> validateBcc(const cppbor::Array* bcc) {
return result;
}
JsonOutput jsonEncodeCsrWithBuild(const cppbor::Array& csr) {
const std::string kFingerprintProp = "ro.build.fingerprint";
if (!::android::base::WaitForPropertyCreation(kFingerprintProp)) {
return JsonOutput::Error("Unable to read build fingerprint");
}
bytevec csrCbor = csr.encode();
size_t base64Length;
int rc = EVP_EncodedLength(&base64Length, csrCbor.size());
if (!rc) {
return JsonOutput::Error("Error getting base64 length. Size overflow?");
}
std::vector<char> base64(base64Length);
rc = EVP_EncodeBlock(reinterpret_cast<uint8_t*>(base64.data()), csrCbor.data(), csrCbor.size());
++rc; // Account for NUL, which BoringSSL does not for some reason.
if (rc != base64Length) {
return JsonOutput::Error("Error writing base64. Expected " + std::to_string(base64Length) +
" bytes to be written, but " + std::to_string(rc) +
" bytes were actually written.");
}
Json::Value json(Json::objectValue);
json["build_fingerprint"] = ::android::base::GetProperty(kFingerprintProp, /*default=*/"");
json["csr"] = base64.data(); // Boring writes a NUL-terminated c-string
Json::StreamWriterBuilder factory;
factory["indentation"] = ""; // disable pretty formatting
return JsonOutput::Ok(Json::writeString(factory, json));
}
} // namespace aidl::android::hardware::security::keymint::remote_prov

View File

@@ -0,0 +1,101 @@
/*
* Copyright 2021 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.
*/
#include <android-base/properties.h>
#include <cppbor_parse.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <keymaster/android_keymaster_utils.h>
#include <keymaster/logger.h>
#include <keymaster/remote_provisioning_utils.h>
#include <openssl/curve25519.h>
#include <remote_prov/remote_prov_utils.h>
#include <cstdint>
#include "cppbor.h"
#include "keymaster/cppcose/cppcose.h"
namespace aidl::android::hardware::security::keymint::remote_prov {
namespace {
using ::keymaster::KeymasterBlob;
using ::keymaster::validateAndExtractEekPubAndId;
using ::testing::ElementsAreArray;
TEST(RemoteProvUtilsTest, GenerateEekChainInvalidLength) {
ASSERT_FALSE(generateEekChain(1, /*eekId=*/{}));
}
TEST(RemoteProvUtilsTest, GenerateEekChain) {
bytevec kTestEekId = {'t', 'e', 's', 't', 'I', 'd', 0};
for (size_t length : {2, 3, 31}) {
auto get_eek_result = generateEekChain(length, kTestEekId);
ASSERT_TRUE(get_eek_result) << get_eek_result.message();
auto& [chain, pubkey, privkey] = *get_eek_result;
auto validation_result = validateAndExtractEekPubAndId(
/*testMode=*/true, KeymasterBlob(chain.data(), chain.size()));
ASSERT_TRUE(validation_result.isOk());
auto& [eekPub, eekId] = *validation_result;
EXPECT_THAT(eekId, ElementsAreArray(kTestEekId));
EXPECT_THAT(eekPub, ElementsAreArray(pubkey));
}
}
TEST(RemoteProvUtilsTest, GetProdEekChain) {
auto chain = getProdEekChain();
auto validation_result = validateAndExtractEekPubAndId(
/*testMode=*/false, KeymasterBlob(chain.data(), chain.size()));
ASSERT_TRUE(validation_result.isOk()) << "Error: " << validation_result.moveError();
auto& [eekPub, eekId] = *validation_result;
auto [geekCert, ignoredNewPos, error] =
cppbor::parse(kCoseEncodedGeekCert, sizeof(kCoseEncodedGeekCert));
ASSERT_NE(geekCert, nullptr) << "Error: " << error;
ASSERT_NE(geekCert->asArray(), nullptr);
auto& encodedGeekCoseKey = geekCert->asArray()->get(kCoseSign1Payload);
ASSERT_NE(encodedGeekCoseKey, nullptr);
ASSERT_NE(encodedGeekCoseKey->asBstr(), nullptr);
auto geek = CoseKey::parse(encodedGeekCoseKey->asBstr()->value());
ASSERT_TRUE(geek) << "Error: " << geek.message();
const std::vector<uint8_t> empty;
EXPECT_THAT(eekId, ElementsAreArray(geek->getBstrValue(CoseKey::KEY_ID).value_or(empty)));
EXPECT_THAT(eekPub, ElementsAreArray(geek->getBstrValue(CoseKey::PUBKEY_X).value_or(empty)));
}
TEST(RemoteProvUtilsTest, JsonEncodeCsr) {
cppbor::Array array;
array.add(1);
auto [json, error] = jsonEncodeCsrWithBuild(array);
ASSERT_TRUE(error.empty()) << error;
std::string expected = R"({"build_fingerprint":")" +
::android::base::GetProperty("ro.build.fingerprint", /*default=*/"") +
R"(","csr":"gQE="})";
ASSERT_EQ(json, expected);
}
} // namespace
} // namespace aidl::android::hardware::security::keymint::remote_prov

View File

@@ -268,10 +268,16 @@ TEST_F(SharedSecretAidlTest, ComputeSharedSecretShortNonce) {
<< "Shared secret service that provided tweaked param should fail to compute "
"shared secret";
} else {
EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
EXPECT_NE(correct_response, responses[i].sharing_check)
<< "Others should calculate a different shared secret, due to the tweaked "
"nonce.";
// Other services *may* succeed, or may notice the invalid size for the nonce.
// However, if another service completes the computation, it should get the 'wrong'
// answer.
if (responses[i].error == ErrorCode::OK) {
EXPECT_NE(correct_response, responses[i].sharing_check)
<< "Others should calculate a different shared secret, due to the tweaked "
"nonce.";
} else {
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error);
}
}
}
}
@@ -348,10 +354,16 @@ TEST_F(SharedSecretAidlTest, ComputeSharedSecretShortSeed) {
<< "Shared secret service that provided tweaked param should fail to compute "
"shared secret";
} else {
EXPECT_EQ(ErrorCode::OK, responses[i].error) << "Others should succeed";
EXPECT_NE(correct_response, responses[i].sharing_check)
<< "Others should calculate a different shared secret, due to the tweaked "
"nonce.";
// Other services *may* succeed, or may notice the invalid size for the seed.
// However, if another service completes the computation, it should get the 'wrong'
// answer.
if (responses[i].error == ErrorCode::OK) {
EXPECT_NE(correct_response, responses[i].sharing_check)
<< "Others should calculate a different shared secret, due to the tweaked "
"seed.";
} else {
EXPECT_EQ(ErrorCode::INVALID_ARGUMENT, responses[i].error);
}
}
}
}

View File

@@ -60,9 +60,10 @@ const std::vector<CompositePrimitive> kCompositePrimitives{
android::enum_range<CompositePrimitive>().begin(),
android::enum_range<CompositePrimitive>().end()};
const std::vector<CompositePrimitive> kOptionalPrimitives = {
CompositePrimitive::THUD,
CompositePrimitive::SPIN,
const std::vector<CompositePrimitive> kRequiredPrimitives = {
CompositePrimitive::CLICK, CompositePrimitive::LIGHT_TICK,
CompositePrimitive::QUICK_RISE, CompositePrimitive::SLOW_RISE,
CompositePrimitive::QUICK_FALL,
};
const std::vector<CompositePrimitive> kInvalidPrimitives = {
@@ -393,11 +394,11 @@ TEST_P(VibratorAidl, GetSupportedPrimitives) {
for (auto primitive : kCompositePrimitives) {
bool isPrimitiveSupported =
std::find(supported.begin(), supported.end(), primitive) != supported.end();
bool isPrimitiveOptional =
std::find(kOptionalPrimitives.begin(), kOptionalPrimitives.end(), primitive) !=
kOptionalPrimitives.end();
bool isPrimitiveRequired =
std::find(kRequiredPrimitives.begin(), kRequiredPrimitives.end(), primitive) !=
kRequiredPrimitives.end();
EXPECT_TRUE(isPrimitiveSupported || isPrimitiveOptional) << toString(primitive);
EXPECT_TRUE(isPrimitiveSupported || !isPrimitiveRequired) << toString(primitive);
}
}
}

View File

@@ -4,6 +4,7 @@ service vendor.wifi_hal_legacy /vendor/bin/hw/android.hardware.wifi@1.0-service-
interface android.hardware.wifi@1.2::IWifi default
interface android.hardware.wifi@1.3::IWifi default
interface android.hardware.wifi@1.4::IWifi default
interface android.hardware.wifi@1.5::IWifi default
oneshot
disabled
class hal

View File

@@ -47,6 +47,11 @@ const std::list<std::vector<uint8_t>>& Ringbuffer::getData() const {
return data_;
}
void Ringbuffer::clear() {
data_.clear();
size_ = 0;
}
} // namespace implementation
} // namespace V1_5
} // namespace wifi

View File

@@ -37,6 +37,7 @@ class Ringbuffer {
// within |maxSize_|.
void append(const std::vector<uint8_t>& input);
const std::list<std::vector<uint8_t>>& getData() const;
void clear();
private:
std::list<std::vector<uint8_t>> data_;

View File

@@ -136,24 +136,25 @@ WifiApIface::getValidFrequenciesForBandInternal(V1_0::WifiBand band) {
WifiStatus WifiApIface::setMacAddressInternal(
const std::array<uint8_t, 6>& mac) {
bool status;
// Support random MAC up to 2 interfaces
if (instances_.size() == 2) {
int rbyte = 1;
for (auto const& intf : instances_) {
std::array<uint8_t, 6> rmac = mac;
// reverse the bits to avoid clision
// reverse the bits to avoid collision
rmac[rbyte] = 0xff - rmac[rbyte];
status = iface_util_.lock()->setMacAddress(intf, rmac);
if (!status) {
if (!iface_util_.lock()->setMacAddress(intf, rmac)) {
LOG(INFO) << "Failed to set random mac address on " << intf;
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
rbyte++;
}
} else {
status = iface_util_.lock()->setMacAddress(ifname_, mac);
}
if (!status) {
// It also needs to set mac address for bridged interface, otherwise the mac
// address of bridged interface will be changed after one of instance
// down.
if (!iface_util_.lock()->setMacAddress(ifname_, mac)) {
LOG(ERROR) << "Fail to config MAC for interface " << ifname_;
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
return createWifiStatus(WifiStatusCode::SUCCESS);
@@ -181,6 +182,18 @@ WifiStatus WifiApIface::resetToFactoryMacAddressInternal() {
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
}
// It needs to set mac address for bridged interface, otherwise the mac
// address of the bridged interface will be changed after one of the
// instance down. Thus we are generating a random MAC address for the
// bridged interface even if we got the request to reset the Factory
// MAC. Since the bridged interface is an internal interface for the
// operation of bpf and others networking operation.
if (!iface_util_.lock()->setMacAddress(
ifname_, iface_util_.lock()->createRandomMacAddress())) {
LOG(ERROR) << "Fail to config MAC for bridged interface "
<< ifname_;
return createWifiStatus(WifiStatusCode::ERROR_UNKNOWN);
}
} else {
getMacResult = getFactoryMacAddressInternal(ifname_);
LOG(DEBUG) << "Reset MAC to factory MAC on " << ifname_;

View File

@@ -1948,8 +1948,8 @@ bool WifiChip::writeRingbufferFilesInternal() {
// write ringbuffers to file
{
std::unique_lock<std::mutex> lk(lock_t);
for (const auto& item : ringbuffer_map_) {
const Ringbuffer& cur_buffer = item.second;
for (auto& item : ringbuffer_map_) {
Ringbuffer& cur_buffer = item.second;
if (cur_buffer.getData().empty()) {
continue;
}
@@ -1967,6 +1967,7 @@ bool WifiChip::writeRingbufferFilesInternal() {
PLOG(ERROR) << "Error writing to file";
}
}
cur_buffer.clear();
}
// unique_lock unlocked here
}

View File

@@ -86,9 +86,9 @@ bool WifiIfaceUtil::setMacAddress(const std::string& iface_name,
event_handlers.on_state_toggle_off_on(iface_name);
}
if (!success) {
LOG(ERROR) << "SetMacAddress failed.";
LOG(ERROR) << "SetMacAddress failed on " << iface_name;
} else {
LOG(DEBUG) << "SetMacAddress succeeded.";
LOG(DEBUG) << "SetMacAddress succeeded on " << iface_name;
}
return success;
}

View File

@@ -71,10 +71,10 @@ class WifiIfaceUtil {
virtual bool removeIfaceFromBridge(const std::string& br_name,
const std::string& if_name);
// Get a random MAC address.
virtual std::array<uint8_t, 6> createRandomMacAddress();
private:
std::array<uint8_t, 6> createRandomMacAddress();
std::weak_ptr<wifi_system::InterfaceTool> iface_tool_;
std::weak_ptr<legacy_hal::WifiLegacyHal> legacy_hal_;
std::unique_ptr<std::array<uint8_t, 6>> random_mac_address_;

View File

@@ -155,5 +155,6 @@ INSTANTIATE_TEST_CASE_P(
testing::ValuesIn(
android::hardware::getAllHalInstanceNames(IWifi::descriptor)),
testing::ValuesIn(android::hardware::getAllHalInstanceNames(
ISupplicant::descriptor))),
android::hardware::wifi::supplicant::V1_4::ISupplicant::
descriptor))),
android::hardware::PrintInstanceTupleNameToString<>);