Merge ab/7633965
Bug: 169893837
Merged-In: I07cf1825c23e2467852d5cd93436eb9dee23b408
Change-Id: Ie9a09f85d7b24b031cb6869429a33ff1eeb84687
diff --git a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
index 28bcd0b..787654b 100644
--- a/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
+++ b/audio/core/all-versions/vts/functional/4.0/AudioPrimaryHidlHalTest.cpp
@@ -332,18 +332,21 @@
#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) {
diff --git a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
index a3dc45b..8cc1882 100644
--- a/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
+++ b/automotive/evs/1.1/vts/functional/VtsHalEvsV1_1TargetTest.cpp
@@ -2269,48 +2269,74 @@
// 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 @@
// 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);
}
diff --git a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
index a85cdf0..f09d75b 100644
--- a/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
+++ b/automotive/vehicle/2.0/default/impl/vhal_v2_0/DefaultConfig.h
@@ -124,7 +124,7 @@
.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 @@
.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 @@
.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 @@
.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 @@
.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 @@
.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 @@
.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 @@
.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 @@
.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 =
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/1/.hash b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/1/.hash
index b8d5097..f5ad87f 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/1/.hash
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/1/.hash
@@ -1 +1 @@
-945de3635b7f5a09244820eef56035c92fdbd324
+3b10f5094c5af9fe551093597fab007d1e148256
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/1/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/1/android/hardware/biometrics/face/ISession.aidl
index d1c2c1d..7817864 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/1/android/hardware/biometrics/face/ISession.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/1/android/hardware/biometrics/face/ISession.aidl
@@ -37,7 +37,7 @@
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();
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl
index d1c2c1d..7817864 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/ISession.aidl
@@ -37,7 +37,7 @@
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();
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentType.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentType.aidl
index d7f3175..c960933 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentType.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/EnrollmentType.aidl
@@ -19,6 +19,15 @@
@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,
}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/FaceSensorType.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/FaceSensorType.aidl
index 57f39d4..a5ed2e8 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/FaceSensorType.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/FaceSensorType.aidl
@@ -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,
+}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl
index 11cdf77..4d7e59e 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl
@@ -25,28 +25,30 @@
/**
* 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);
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
index a9a8c16..5f06b40 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
@@ -24,13 +24,12 @@
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 @@
* | 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 @@
/**
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
/*
* 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 @@
* 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 @@
*
* 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 @@
* 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 @@
* 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 @@
* 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 @@
*
* 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 @@
* 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 @@
* 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();
}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl
index 23570bd..b3c348d 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISessionCallback.aidl
@@ -37,11 +37,11 @@
/**
* 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 @@
* 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 @@
/**
* 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
diff --git a/biometrics/face/aidl/default/Session.cpp b/biometrics/face/aidl/default/Session.cpp
index d980c5f..01cb620 100644
--- a/biometrics/face/aidl/default/Session.cpp
+++ b/biometrics/face/aidl/default/Session.cpp
@@ -34,12 +34,15 @@
}
};
-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::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::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::invalidateAuthenticatorId() {
LOG(INFO) << "invalidateAuthenticatorId";
+ if (cb_) {
+ cb_->onAuthenticatorIdInvalidated(0);
+ }
return ndk::ScopedAStatus::ok();
}
diff --git a/biometrics/face/aidl/default/Session.h b/biometrics/face/aidl/default/Session.h
index caf81f8..4152909 100644
--- a/biometrics/face/aidl/default/Session.h
+++ b/biometrics/face/aidl/default/Session.h
@@ -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 @@
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 @@
private:
std::shared_ptr<ISessionCallback> cb_;
+ std::mt19937 mRandom;
};
} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/vts/VtsHalBiometricsFaceTargetTest.cpp b/biometrics/face/aidl/vts/VtsHalBiometricsFaceTargetTest.cpp
index 47a7813..08ab5d6 100644
--- a/biometrics/face/aidl/vts/VtsHalBiometricsFaceTargetTest.cpp
+++ b/biometrics/face/aidl/vts/VtsHalBiometricsFaceTargetTest.cpp
@@ -29,16 +29,26 @@
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 @@
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 @@
}
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 @@
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);
diff --git a/biometrics/fingerprint/2.3/IBiometricsFingerprint.hal b/biometrics/fingerprint/2.3/IBiometricsFingerprint.hal
index 13f03c5..378b564 100644
--- a/biometrics/fingerprint/2.3/IBiometricsFingerprint.hal
+++ b/biometrics/fingerprint/2.3/IBiometricsFingerprint.hal
@@ -19,6 +19,10 @@
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 {
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
index 271a9bf..75f90a1 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/IFingerprint.aidl
@@ -25,31 +25,31 @@
/**
* 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);
}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
index 02ef138..f1d96d3 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISession.aidl
@@ -20,30 +20,29 @@
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 @@
* | 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
*
* 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 @@
* 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 @@
* 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 @@
/**
* 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 @@
/**
* 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 @@
/*
* 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();
}
diff --git a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
index 95657b3..f699966 100644
--- a/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
+++ b/biometrics/fingerprint/aidl/android/hardware/biometrics/fingerprint/ISessionCallback.aidl
@@ -34,12 +34,12 @@
/**
* 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 @@
/**
* 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 @@
* 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();
diff --git a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
index 6667f7a..b927770 100644
--- a/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
+++ b/biometrics/fingerprint/aidl/default/include/FakeFingerprintEngine.h
@@ -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 @@
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 @@
LOG(INFO) << "resetLockoutImpl";
cb->onLockoutCleared();
}
+
+ std::mt19937 mRandom;
};
} // namespace aidl::android::hardware::biometrics::fingerprint
diff --git a/biometrics/fingerprint/aidl/vts/VtsHalBiometricsFingerprintTargetTest.cpp b/biometrics/fingerprint/aidl/vts/VtsHalBiometricsFingerprintTargetTest.cpp
index f1cfb17..1cd8c76 100644
--- a/biometrics/fingerprint/aidl/vts/VtsHalBiometricsFingerprintTargetTest.cpp
+++ b/biometrics/fingerprint/aidl/vts/VtsHalBiometricsFingerprintTargetTest.cpp
@@ -35,13 +35,19 @@
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 @@
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 @@
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);
diff --git a/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.cpp b/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.cpp
index f71a73e..0c0b85f 100644
--- a/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.cpp
+++ b/bluetooth/audio/2.0/default/A2dpSoftwareAudioProvider.cpp
@@ -32,10 +32,14 @@
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;
diff --git a/bluetooth/audio/2.1/default/A2dpSoftwareAudioProvider.cpp b/bluetooth/audio/2.1/default/A2dpSoftwareAudioProvider.cpp
index a37176b..4928cea 100644
--- a/bluetooth/audio/2.1/default/A2dpSoftwareAudioProvider.cpp
+++ b/bluetooth/audio/2.1/default/A2dpSoftwareAudioProvider.cpp
@@ -34,10 +34,14 @@
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;
diff --git a/camera/device/3.7/types.hal b/camera/device/3.7/types.hal
index 6910e65..55aceb8 100644
--- a/camera/device/3.7/types.hal
+++ b/camera/device/3.7/types.hal
@@ -42,7 +42,7 @@
/**
* 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
diff --git a/camera/metadata/3.2/types.hal b/camera/metadata/3.2/types.hal
index ad671d9..4b02830 100644
--- a/camera/metadata/3.2/types.hal
+++ b/camera/metadata/3.2/types.hal
@@ -686,7 +686,9 @@
/** 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,
diff --git a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
index 41a08f9..49e00f4 100644
--- a/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
+++ b/camera/provider/2.4/vts/functional/VtsHalCameraProviderV2_4TargetTest.cpp
@@ -230,10 +230,10 @@
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 @@
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 @@
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 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 @@
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,
diff --git a/current.txt b/current.txt
index 908ecc4..8c631d9 100644
--- a/current.txt
+++ b/current.txt
@@ -768,6 +768,8 @@
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 @@
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 @@
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
diff --git a/gnss/1.1/default/Gnss.cpp b/gnss/1.1/default/Gnss.cpp
index 5043649..0d77ce4 100644
--- a/gnss/1.1/default/Gnss.cpp
+++ b/gnss/1.1/default/Gnss.cpp
@@ -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 @@
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<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++) {
diff --git a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
index fcab8c4..8fa5f7e 100644
--- a/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
+++ b/gnss/2.1/vts/functional/gnss_hal_test_cases.cpp
@@ -249,35 +249,40 @@
/*
* 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();
}
diff --git a/gnss/common/utils/default/Utils.cpp b/gnss/common/utils/default/Utils.cpp
index 569dac4..d136448 100644
--- a/gnss/common/utils/default/Utils.cpp
+++ b/gnss/common/utils/default/Utils.cpp
@@ -265,50 +265,50 @@
}
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 @@
}
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 @@
};
GnssAntennaInfo mockAntennaInfo_2 = {
- .carrierFrequencyMHz = 532324.23,
+ .carrierFrequencyMHz = kGpsL5FreqHz * 1e-6,
.phaseCenterOffsetCoordinateMillimeters = Coord{.x = 5,
.xUncertainty = 0.1,
.y = 6,
diff --git a/gnss/common/utils/default/include/Constants.h b/gnss/common/utils/default/include/Constants.h
index a290ed2..22afee1 100644
--- a/gnss/common/utils/default/include/Constants.h
+++ b/gnss/common/utils/default/include/Constants.h
@@ -29,6 +29,10 @@
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
diff --git a/gnss/common/utils/default/include/Utils.h b/gnss/common/utils/default/include/Utils.h
index 771d39d..43772ce 100644
--- a/gnss/common/utils/default/include/Utils.h
+++ b/gnss/common/utils/default/include/Utils.h
@@ -44,7 +44,8 @@
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();
};
diff --git a/gnss/common/utils/default/include/v2_1/GnssTemplate.h b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
index a1d6981..131af24 100644
--- a/gnss/common/utils/default/include/v2_1/GnssTemplate.h
+++ b/gnss/common/utils/default/include/v2_1/GnssTemplate.h
@@ -113,6 +113,7 @@
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 @@
}
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 @@
Return<bool> GnssTemplate<T_IGnss>::stop() {
ALOGD("stop");
mIsActive = false;
+ this->reportGnssStatusValue(V1_0::IGnssCallback::GnssStatusValue::SESSION_END);
if (mThread.joinable()) {
mThread.join();
}
@@ -606,6 +609,20 @@
}
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 {
std::unique_lock<std::mutex> lock(mMutex);
diff --git a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
index 7a1568b..7a053f1 100644
--- a/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
+++ b/graphics/composer/2.2/vts/functional/VtsHalGraphicsComposerV2_2ReadbackTest.cpp
@@ -458,6 +458,7 @@
<< " pixel format: PixelFormat::RGBA_8888 dataspace: "
<< ReadbackHelper::getDataspaceString(clientDataspace)
<< " unsupported for display" << std::endl;
+ mReader->mCompositionChanges.clear();
continue;
}
diff --git a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
index 54ba79d..ecfe66c 100644
--- a/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
+++ b/graphics/composer/2.3/vts/functional/VtsHalGraphicsComposerV2_3TargetTest.cpp
@@ -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 @@
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";
}
/**
diff --git a/graphics/composer/2.4/vts/functional/AndroidTest.xml b/graphics/composer/2.4/vts/functional/AndroidTest.xml
index 583aa68..773db93 100644
--- a/graphics/composer/2.4/vts/functional/AndroidTest.xml
+++ b/graphics/composer/2.4/vts/functional/AndroidTest.xml
@@ -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>
diff --git a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
index 01c502c..476eed8 100644
--- a/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
+++ b/keymaster/4.0/vts/functional/keymaster_hidl_hal_test.cpp
@@ -438,7 +438,7 @@
// 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) {
diff --git a/memtrack/aidl/android/hardware/memtrack/IMemtrack.aidl b/memtrack/aidl/android/hardware/memtrack/IMemtrack.aidl
index e78d4d7..88b090b 100644
--- a/memtrack/aidl/android/hardware/memtrack/IMemtrack.aidl
+++ b/memtrack/aidl/android/hardware/memtrack/IMemtrack.aidl
@@ -31,21 +31,36 @@
* 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().
*/
diff --git a/neuralnetworks/aidl/utils/src/Device.cpp b/neuralnetworks/aidl/utils/src/Device.cpp
index 0fd453b..e80de0b 100644
--- a/neuralnetworks/aidl/utils/src/Device.cpp
+++ b/neuralnetworks/aidl/utils/src/Device.cpp
@@ -119,7 +119,7 @@
<< numberOfCacheFiles.numDataCache << " vs " << nn::kMaxNumberOfCacheFiles
<< ")";
}
- return std::make_pair(numberOfCacheFiles.numDataCache, numberOfCacheFiles.numModelCache);
+ return std::make_pair(numberOfCacheFiles.numModelCache, numberOfCacheFiles.numDataCache);
}
} // namespace
diff --git a/neuralnetworks/aidl/utils/test/DeviceTest.cpp b/neuralnetworks/aidl/utils/test/DeviceTest.cpp
index e53b0a8..f121aca 100644
--- a/neuralnetworks/aidl/utils/test/DeviceTest.cpp
+++ b/neuralnetworks/aidl/utils/test/DeviceTest.cpp
@@ -58,7 +58,7 @@
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 @@
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();
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
index 0b49b36..d108951 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.5/vts/functional/radio_hidl_hal_api.cpp
@@ -1251,8 +1251,20 @@
* 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);
diff --git a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
index 87ce675..65442ca 100644
--- a/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
+++ b/radio/1.5/vts/functional/radio_hidl_hal_utils_v1_5.h
@@ -51,6 +51,8 @@
#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 @@
// Call
hidl_vec<::android::hardware::radio::V1_2::Call> currentCalls;
+ ::android::hardware::radio::V1_2::VoiceRegStateResult voiceRegResp;
// Modem
bool isModemEnabled;
diff --git a/radio/1.5/vts/functional/radio_response.cpp b/radio/1.5/vts/functional/radio_response.cpp
index 9b6d450..3d6fc17 100644
--- a/radio/1.5/vts/functional/radio_response.cpp
+++ b/radio/1.5/vts/functional/radio_response.cpp
@@ -763,8 +763,9 @@
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::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();
}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl b/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
index 32d69cd..b0761bf 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl
@@ -44,6 +44,12 @@
* ? "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;
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 9cc795d..2241735 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -277,6 +277,10 @@
* 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 @@
* 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 @@
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.
*
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl b/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
index 31dbb28..24cdbc1 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl
@@ -158,20 +158,7 @@
* 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
diff --git a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
index 58e02b3..67a0214 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/Tag.aidl
@@ -18,10 +18,6 @@
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 @@
/**
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
* 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 @@
*
* 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 @@
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* Must be hardware-enforced.
*/
- ORIGIN = (1 << 28) /* TagType:ENUM */ | 702,
+ ORIGIN = TagType.ENUM | 702,
// 703 is unused.
@@ -567,7 +567,7 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
* 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 @@
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
*
* 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 @@
* 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 @@
* 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 @@
* 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 @@
* 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 @@
*
* Cannot be hardware enforced in this version.
*/
- MAX_BOOT_LEVEL = (3 << 28) /* TagType:UINT */ | 1010,
+ MAX_BOOT_LEVEL = TagType.UINT | 1010,
}
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index ff08ce6..77eea8a 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -23,16 +23,11 @@
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 @@
"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_library {
name: "libkeymint_vts_test_utils",
defaults: [
- "VtsHalTargetTestDefaults",
- "use_libaidlvintf_gtest_helper_static",
+ "keymint_vts_defaults",
],
srcs: [
"KeyMintAidlTestBase.cpp",
@@ -66,48 +75,26 @@
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",
diff --git a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
index a3ed3ad..d7abf07 100644
--- a/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
+++ b/security/keymint/aidl/vts/functional/DeviceUniqueAttestationTest.cpp
@@ -40,11 +40,16 @@
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,
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index 5359b3b..2032411 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -1493,7 +1493,8 @@
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 @@
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
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index d592d36..ec3fcf6 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -349,7 +349,8 @@
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, \
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index d41d270..5a87b83 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -1487,9 +1487,8 @@
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 @@
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;
}
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 78f8f08..38f3586 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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,31 +395,62 @@
}
/**
- * 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.
*/
TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
@@ -420,13 +459,13 @@
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 @@
}
/**
- * 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 @@
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 @@
* 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 @@
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 @@
/**
* 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 @@
// 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 @@
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 @@
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(),
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.xml b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.xml
new file mode 100644
index 0000000..2375bde
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.xml
@@ -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>
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index 718133a..9e218b6 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -57,8 +57,28 @@
"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",
],
}
diff --git a/security/keymint/support/include/remote_prov/remote_prov_utils.h b/security/keymint/support/include/remote_prov/remote_prov_utils.h
index e4261f3..406b7a9 100644
--- a/security/keymint/support/include/remote_prov/remote_prov_utils.h
+++ b/security/keymint/support/include/remote_prov/remote_prov_utils.h
@@ -27,6 +27,31 @@
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 @@
*/
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 @@
*/
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
diff --git a/security/keymint/support/remote_prov_utils.cpp b/security/keymint/support/remote_prov_utils.cpp
index 33f1ed3..0cbee51 100644
--- a/security/keymint/support/remote_prov_utils.cpp
+++ b/security/keymint/support/remote_prov_utils.cpp
@@ -14,11 +14,15 @@
* limitations under the License.
*/
-#include <remote_prov/remote_prov_utils.h>
+#include <iterator>
+#include <tuple>
-#include <openssl/rand.h>
-
+#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 @@
}
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 @@
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 @@
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
diff --git a/security/keymint/support/remote_prov_utils_test.cpp b/security/keymint/support/remote_prov_utils_test.cpp
new file mode 100644
index 0000000..8697c51
--- /dev/null
+++ b/security/keymint/support/remote_prov_utils_test.cpp
@@ -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
diff --git a/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp b/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
index 919f882..51938ba 100644
--- a/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
+++ b/security/sharedsecret/aidl/vts/functional/SharedSecretAidlTest.cpp
@@ -268,10 +268,16 @@
<< "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 @@
<< "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);
+ }
}
}
}
diff --git a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
index c56bd9a..553d7f0 100644
--- a/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
+++ b/vibrator/aidl/vts/VtsHalVibratorTargetTest.cpp
@@ -60,9 +60,10 @@
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 @@
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);
}
}
}
diff --git a/wifi/1.5/default/android.hardware.wifi@1.0-service-lazy.rc b/wifi/1.5/default/android.hardware.wifi@1.0-service-lazy.rc
index 061689d..bc6bb6a 100644
--- a/wifi/1.5/default/android.hardware.wifi@1.0-service-lazy.rc
+++ b/wifi/1.5/default/android.hardware.wifi@1.0-service-lazy.rc
@@ -4,6 +4,7 @@
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
diff --git a/wifi/1.5/default/ringbuffer.cpp b/wifi/1.5/default/ringbuffer.cpp
index 26971ff..f554111 100644
--- a/wifi/1.5/default/ringbuffer.cpp
+++ b/wifi/1.5/default/ringbuffer.cpp
@@ -47,6 +47,11 @@
return data_;
}
+void Ringbuffer::clear() {
+ data_.clear();
+ size_ = 0;
+}
+
} // namespace implementation
} // namespace V1_5
} // namespace wifi
diff --git a/wifi/1.5/default/ringbuffer.h b/wifi/1.5/default/ringbuffer.h
index d8b87f2..03fb37a 100644
--- a/wifi/1.5/default/ringbuffer.h
+++ b/wifi/1.5/default/ringbuffer.h
@@ -37,6 +37,7 @@
// 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_;
diff --git a/wifi/1.5/default/wifi_ap_iface.cpp b/wifi/1.5/default/wifi_ap_iface.cpp
index b438a4a..1ae7905 100644
--- a/wifi/1.5/default/wifi_ap_iface.cpp
+++ b/wifi/1.5/default/wifi_ap_iface.cpp
@@ -136,24 +136,25 @@
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 @@
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_;
diff --git a/wifi/1.5/default/wifi_chip.cpp b/wifi/1.5/default/wifi_chip.cpp
index 6fa9601..82d794c 100644
--- a/wifi/1.5/default/wifi_chip.cpp
+++ b/wifi/1.5/default/wifi_chip.cpp
@@ -1948,8 +1948,8 @@
// 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 @@
PLOG(ERROR) << "Error writing to file";
}
}
+ cur_buffer.clear();
}
// unique_lock unlocked here
}
diff --git a/wifi/1.5/default/wifi_iface_util.cpp b/wifi/1.5/default/wifi_iface_util.cpp
index d1434e3..7bf830b 100644
--- a/wifi/1.5/default/wifi_iface_util.cpp
+++ b/wifi/1.5/default/wifi_iface_util.cpp
@@ -86,9 +86,9 @@
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;
}
diff --git a/wifi/1.5/default/wifi_iface_util.h b/wifi/1.5/default/wifi_iface_util.h
index b449077..544f575 100644
--- a/wifi/1.5/default/wifi_iface_util.h
+++ b/wifi/1.5/default/wifi_iface_util.h
@@ -71,10 +71,10 @@
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_;
diff --git a/wifi/supplicant/1.4/vts/functional/supplicant_sta_network_hidl_test.cpp b/wifi/supplicant/1.4/vts/functional/supplicant_sta_network_hidl_test.cpp
index e3fbaf3..49d471b 100644
--- a/wifi/supplicant/1.4/vts/functional/supplicant_sta_network_hidl_test.cpp
+++ b/wifi/supplicant/1.4/vts/functional/supplicant_sta_network_hidl_test.cpp
@@ -155,5 +155,6 @@
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<>);