Merge changes from topic "IFingerprint-explicit-close" into sc-dev
* changes:
Update default HAL with close and reset methods
Add IFingerprint#reset and ISession#close methods
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/IFace.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/IFace.aidl
index 37345ec..bfaf90d 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/IFace.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/IFace.aidl
@@ -35,4 +35,5 @@
interface IFace {
android.hardware.biometrics.face.SensorProps[] getSensorProps();
android.hardware.biometrics.face.ISession createSession(in int sensorId, in int userId, in android.hardware.biometrics.face.ISessionCallback cb);
+ void reset();
}
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 b855a9e..c9165e1 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
@@ -45,4 +45,5 @@
void getAuthenticatorId(in int cookie);
void invalidateAuthenticatorId(in int cookie);
void resetLockout(in int cookie, in android.hardware.keymaster.HardwareAuthToken hat);
+ void close(in int cookie);
}
diff --git a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
index 46751d0..3792eae 100644
--- a/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
+++ b/biometrics/face/aidl/aidl_api/android.hardware.biometrics.face/current/android/hardware/biometrics/face/SessionState.aidl
@@ -34,7 +34,7 @@
@Backing(type="byte") @VintfStability
enum SessionState {
IDLING = 0,
- TERMINATED = 1,
+ CLOSED = 1,
GENERATING_CHALLENGE = 2,
REVOKING_CHALLENGE = 3,
ENROLLING = 4,
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl
index f9ed4b1..afb7c8d 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/IFace.aidl
@@ -35,6 +35,10 @@
* Creates a session that can be used by the framework to perform operations such as
* enroll, 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.
+ *
* 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
@@ -47,4 +51,13 @@
*/
ISession createSession(in int sensorId, in int userId, in ISessionCallback cb);
+ /**
+ * Resets the HAL into a clean state, forcing it to cancel all of the pending operations, close
+ * its current session, and release all of the acquired resources.
+ *
+ * This should be used as a last resort to recover the HAL if the current session becomes
+ * unresponsive. The implementation might choose to restart the HAL process to get back into a
+ * good state.
+ */
+ void reset();
}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
index f540502..6f2014a 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/ISession.aidl
@@ -17,19 +17,20 @@
package android.hardware.biometrics.face;
import android.hardware.biometrics.common.ICancellationSignal;
-import android.hardware.biometrics.face.Feature;
import android.hardware.biometrics.face.EnrollmentType;
-import android.hardware.keymaster.HardwareAuthToken;
+import android.hardware.biometrics.face.Feature;
import android.hardware.common.NativeHandle;
+import android.hardware.keymaster.HardwareAuthToken;
-/** * A session is a collection of immutable state (sensorId, userId), mutable state (SessionState),
+/**
+ * A session is a collection of immutable state (sensorId, userId), mutable state (SessionState),
* methods available for the framework to call, and a callback (ISessionCallback) to notify the
* framework about the events and results. A session is used to establish communication between
* the framework and the HAL.
*/
@VintfStability
interface ISession {
- /**
+ /**
* generateChallenge:
*
* Begins a secure transaction request. Note that the challenge by itself is not useful. It only
@@ -134,9 +135,9 @@
* @param hat See above documentation.
* @param enrollmentType See the EnrollmentType enum.
* @param features See the Feature enum.
- * @param previewSurface A surface provided by the framework if SensorProps#halControlsPreview is
- * set to true. The HAL must send the preview frames to previewSurface if
- * it's not null.
+ * @param previewSurface A surface provided by the framework if SensorProps#halControlsPreview
+ * is set to true. The HAL must send the preview frames to previewSurface
+ * if it's not null.
* @return ICancellationSignal An object that can be used by the framework to cancel this
* operation.
*/
@@ -420,5 +421,22 @@
* @param hat HardwareAuthToken See above documentation.
*/
void resetLockout(in int cookie, in HardwareAuthToken hat);
-}
+ /*
+ * Close this session and allow the HAL to release the resources associated with this session.
+ *
+ * A session can only be closed when it's in SessionState::IDLING. Closing a session will
+ * result in a ISessionCallback#onStateChanged call with SessionState::CLOSED.
+ *
+ * If a session is unresponsive or stuck in a state other than SessionState::CLOSED,
+ * IFace#reset could be used as a last resort to terminate the session and recover the HAL
+ * from a bad state.
+ *
+ * All sessions must be explicitly closed. Calling IFace#createSession while there is an active
+ * session is considered an error.
+ *
+ * @param cookie An identifier used to track subsystem operations related to this call path. The
+ * client must guarantee that it is unique per ISession.
+ */
+ void close(in int cookie);
+}
diff --git a/biometrics/face/aidl/android/hardware/biometrics/face/SessionState.aidl b/biometrics/face/aidl/android/hardware/biometrics/face/SessionState.aidl
index 7675564..afde4eb 100644
--- a/biometrics/face/aidl/android/hardware/biometrics/face/SessionState.aidl
+++ b/biometrics/face/aidl/android/hardware/biometrics/face/SessionState.aidl
@@ -25,9 +25,9 @@
IDLING,
/**
- * The session has been terminated by the HAL.
+ * The session has been closed by the client.
*/
- TERMINATED,
+ CLOSED,
/**
* The HAL is processing the ISession#generateChallenge request.
@@ -89,4 +89,3 @@
*/
RESETTING_LOCKOUT
}
-
diff --git a/biometrics/face/aidl/default/Face.cpp b/biometrics/face/aidl/default/Face.cpp
index 773359e..2b40850 100644
--- a/biometrics/face/aidl/default/Face.cpp
+++ b/biometrics/face/aidl/default/Face.cpp
@@ -63,4 +63,8 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Face::reset() {
+ return ndk::ScopedAStatus::ok();
+}
+
} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/Face.h b/biometrics/face/aidl/default/Face.h
index 786b4f8..809b856 100644
--- a/biometrics/face/aidl/default/Face.h
+++ b/biometrics/face/aidl/default/Face.h
@@ -27,6 +27,8 @@
ndk::ScopedAStatus createSession(int32_t sensorId, int32_t userId,
const std::shared_ptr<ISessionCallback>& cb,
std::shared_ptr<ISession>* _aidl_return) override;
+
+ ndk::ScopedAStatus reset() override;
};
} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/Session.cpp b/biometrics/face/aidl/default/Session.cpp
index bd5a062..a7130e6 100644
--- a/biometrics/face/aidl/default/Session.cpp
+++ b/biometrics/face/aidl/default/Session.cpp
@@ -142,4 +142,8 @@
return ndk::ScopedAStatus::ok();
}
+ndk::ScopedAStatus Session::close(int32_t /*cookie*/) {
+ return ndk::ScopedAStatus::ok();
+}
+
} // namespace aidl::android::hardware::biometrics::face
diff --git a/biometrics/face/aidl/default/Session.h b/biometrics/face/aidl/default/Session.h
index 83cb064..0651726 100644
--- a/biometrics/face/aidl/default/Session.h
+++ b/biometrics/face/aidl/default/Session.h
@@ -63,6 +63,8 @@
ndk::ScopedAStatus resetLockout(int32_t cookie,
const keymaster::HardwareAuthToken& hat) override;
+ ndk::ScopedAStatus close(int32_t cookie) override;
+
private:
std::shared_ptr<ISessionCallback> cb_;
};
diff --git a/camera/metadata/3.6/Android.bp b/camera/metadata/3.6/Android.bp
new file mode 100644
index 0000000..d9f3fb8
--- /dev/null
+++ b/camera/metadata/3.6/Android.bp
@@ -0,0 +1,16 @@
+// This file is autogenerated by hidl-gen -Landroidbp.
+
+hidl_interface {
+ name: "android.hardware.camera.metadata@3.6",
+ root: "android.hardware",
+ srcs: [
+ "types.hal",
+ ],
+ interfaces: [
+ "android.hardware.camera.metadata@3.2",
+ "android.hardware.camera.metadata@3.3",
+ "android.hardware.camera.metadata@3.4",
+ "android.hardware.camera.metadata@3.5",
+ ],
+ gen_java: true,
+}
diff --git a/camera/metadata/3.6/types.hal b/camera/metadata/3.6/types.hal
new file mode 100644
index 0000000..fb95736
--- /dev/null
+++ b/camera/metadata/3.6/types.hal
@@ -0,0 +1,51 @@
+/*
+ * 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.
+ */
+
+/*
+ * Autogenerated from camera metadata definitions in
+ * /system/media/camera/docs/metadata_definitions.xml
+ * *** DO NOT EDIT BY HAND ***
+ */
+
+package android.hardware.camera.metadata@3.6;
+
+import android.hardware.camera.metadata@3.2;
+import android.hardware.camera.metadata@3.3;
+import android.hardware.camera.metadata@3.4;
+import android.hardware.camera.metadata@3.5;
+
+// No new metadata sections added in this revision
+
+/**
+ * Main enumeration for defining camera metadata tags added in this revision
+ *
+ * <p>Partial documentation is included for each tag; for complete documentation, reference
+ * '/system/media/camera/docs/docs.html' in the corresponding Android source tree.</p>
+ */
+enum CameraMetadataTag : @3.5::CameraMetadataTag {
+ /** android.scaler.defaultSecureImageSize [static, int32[], public]
+ *
+ * <p>Default YUV/PRIVATE size to use for requesting secure image buffers.</p>
+ */
+ ANDROID_SCALER_DEFAULT_SECURE_IMAGE_SIZE = android.hardware.camera.metadata@3.5::CameraMetadataTag:ANDROID_SCALER_END_3_5,
+
+ ANDROID_SCALER_END_3_6,
+
+};
+
+/*
+ * Enumeration definitions for the various entries that need them
+ */
diff --git a/compatibility_matrices/compatibility_matrix.5.xml b/compatibility_matrices/compatibility_matrix.5.xml
index e772b6f..96a3692 100644
--- a/compatibility_matrices/compatibility_matrix.5.xml
+++ b/compatibility_matrices/compatibility_matrix.5.xml
@@ -86,7 +86,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.biometrics.face</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IBiometricsFace</name>
<instance>default</instance>
diff --git a/compatibility_matrices/compatibility_matrix.current.xml b/compatibility_matrices/compatibility_matrix.current.xml
index e500a29..6562f22 100644
--- a/compatibility_matrices/compatibility_matrix.current.xml
+++ b/compatibility_matrices/compatibility_matrix.current.xml
@@ -95,7 +95,7 @@
</hal>
<hal format="hidl" optional="true">
<name>android.hardware.biometrics.face</name>
- <version>1.0-1</version>
+ <version>1.0</version>
<interface>
<name>IBiometricsFace</name>
<instance>default</instance>
diff --git a/drm/1.4/vts/functional/drm_hal_test.cpp b/drm/1.4/vts/functional/drm_hal_test.cpp
index ee6635b..f9fa0bd 100644
--- a/drm/1.4/vts/functional/drm_hal_test.cpp
+++ b/drm/1.4/vts/functional/drm_hal_test.cpp
@@ -154,6 +154,42 @@
EXPECT_TRUE(foundPbId);
}
+TEST_P(DrmHalTest, GetLogMessages) {
+ auto drm = DrmPluginV1_4();
+ auto sid = OpenSession();
+ auto crypto_1_0 = CryptoPlugin(sid);
+ sp<V1_4::ICryptoPlugin> crypto(V1_4::ICryptoPlugin::castFrom(crypto_1_0));
+
+ hidl_vec<uint8_t> initData;
+ hidl_string mime{"text/plain"};
+ V1_0::KeyedVector optionalParameters;
+ auto res = drmPlugin->getKeyRequest_1_2(
+ sid, initData, mime, V1_0::KeyType::STREAMING,
+ optionalParameters, [&](V1_2::Status status, const hidl_vec<uint8_t>&,
+ V1_1::KeyRequestType, const hidl_string&) {
+ EXPECT_NE(V1_2::Status::OK, status);
+ });
+ EXPECT_OK(res);
+
+ V1_4::IDrmPlugin::getLogMessages_cb cb = [&](
+ V1_4::Status status,
+ hidl_vec<V1_4::LogMessage> logs) {
+ EXPECT_EQ(V1_4::Status::OK, status);
+ EXPECT_NE(0, logs.size());
+ for (auto log: logs) {
+ ALOGI("priority=[%u] message='%s'", log.priority, log.message.c_str());
+ }
+ };
+
+ auto res2 = drm->getLogMessages(cb);
+ EXPECT_OK(res2);
+
+ auto res3 = crypto->getLogMessages(cb);
+ EXPECT_OK(res3);
+
+ closeSession(sid);
+}
+
} // namespace vts
} // namespace V1_4
} // namespace drm
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index 91985ce..6418028 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -833,9 +833,16 @@
optional<vector<vector<uint8_t>>> createAttestation(
const EVP_PKEY* key, const vector<uint8_t>& applicationId, const vector<uint8_t>& challenge,
uint64_t activeTimeMilliSeconds, uint64_t expireTimeMilliSeconds, bool isTestCredential) {
+ // Pretend to be implemented in a trusted environment just so we can pass
+ // the VTS tests. Of course, this is a pretend-only game since hopefully no
+ // relying party is ever going to trust our batch key and those keys above
+ // it.
+ ::keymaster::PureSoftKeymasterContext context(::keymaster::KmVersion::KEYMASTER_4_1,
+ KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
+
keymaster_error_t error;
::keymaster::CertificateChain attestation_chain =
- ::keymaster::getAttestationChain(KM_ALGORITHM_EC, &error);
+ context.GetAttestationChain(KM_ALGORITHM_EC, &error);
if (KM_ERROR_OK != error) {
LOG(ERROR) << "Error getting attestation chain " << error;
return {};
@@ -855,12 +862,6 @@
}
expireTimeMilliSeconds = bcNotAfter * 1000;
}
- const keymaster_key_blob_t* attestation_signing_key =
- ::keymaster::getAttestationKey(KM_ALGORITHM_EC, nullptr);
- if (attestation_signing_key == nullptr) {
- LOG(ERROR) << "Error getting attestation key";
- return {};
- }
::keymaster::X509_NAME_Ptr subjectName;
if (KM_ERROR_OK !=
@@ -917,16 +918,8 @@
}
::keymaster::AuthorizationSet hwEnforced(hwEnforcedBuilder);
- // Pretend to be implemented in a trusted environment just so we can pass
- // the VTS tests. Of course, this is a pretend-only game since hopefully no
- // relying party is ever going to trust our batch key and those keys above
- // it.
- ::keymaster::PureSoftKeymasterContext context(::keymaster::KmVersion::KEYMINT_1,
- KM_SECURITY_LEVEL_TRUSTED_ENVIRONMENT);
-
- ::keymaster::CertificateChain cert_chain_out = generate_attestation_from_EVP(
- key, swEnforced, hwEnforced, auth_set, context, move(attestation_chain),
- *attestation_signing_key, &error);
+ ::keymaster::CertificateChain cert_chain_out = generate_attestation(
+ key, swEnforced, hwEnforced, auth_set, {} /* attest_key */, context, &error);
if (KM_ERROR_OK != error) {
LOG(ERROR) << "Error generating attestation from EVP key: " << error;
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h
index f2cbe93..8329303 100644
--- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h
@@ -41,7 +41,7 @@
Burst(PrivateConstructorTag tag, nn::SharedPreparedModel preparedModel);
- OptionalCacheHold cacheMemory(const nn::Memory& memory) const override;
+ OptionalCacheHold cacheMemory(const nn::SharedMemory& memory) const override;
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
const nn::Request& request, nn::MeasureTiming measure) const override;
diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Conversions.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Conversions.h
index d3d933b..5d4bdbc 100644
--- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Conversions.h
+++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Conversions.h
@@ -36,7 +36,7 @@
GeneralResult<Operation> unvalidatedConvert(const hal::V1_0::Operation& operation);
GeneralResult<Model::OperandValues> unvalidatedConvert(
const hardware::hidl_vec<uint8_t>& operandValues);
-GeneralResult<Memory> unvalidatedConvert(const hardware::hidl_memory& memory);
+GeneralResult<SharedMemory> unvalidatedConvert(const hardware::hidl_memory& memory);
GeneralResult<Model> unvalidatedConvert(const hal::V1_0::Model& model);
GeneralResult<Request::Argument> unvalidatedConvert(
const hal::V1_0::RequestArgument& requestArgument);
@@ -65,7 +65,7 @@
nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation);
nn::GeneralResult<hidl_vec<uint8_t>> unvalidatedConvert(
const nn::Model::OperandValues& operandValues);
-nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::Memory& memory);
+nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::SharedMemory& memory);
nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model);
nn::GeneralResult<RequestArgument> unvalidatedConvert(const nn::Request::Argument& requestArgument);
nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::Request::MemoryPool& memoryPool);
diff --git a/neuralnetworks/1.0/utils/src/Burst.cpp b/neuralnetworks/1.0/utils/src/Burst.cpp
index 384bd9b..971ad08 100644
--- a/neuralnetworks/1.0/utils/src/Burst.cpp
+++ b/neuralnetworks/1.0/utils/src/Burst.cpp
@@ -43,7 +43,7 @@
CHECK(kPreparedModel != nullptr);
}
-Burst::OptionalCacheHold Burst::cacheMemory(const nn::Memory& /*memory*/) const {
+Burst::OptionalCacheHold Burst::cacheMemory(const nn::SharedMemory& /*memory*/) const {
return nullptr;
}
diff --git a/neuralnetworks/1.0/utils/src/Conversions.cpp b/neuralnetworks/1.0/utils/src/Conversions.cpp
index fde7346..7a099cf 100644
--- a/neuralnetworks/1.0/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.0/utils/src/Conversions.cpp
@@ -153,8 +153,8 @@
return Model::OperandValues(operandValues.data(), operandValues.size());
}
-GeneralResult<Memory> unvalidatedConvert(const hidl_memory& memory) {
- return createSharedMemoryFromHidlMemory(memory);
+GeneralResult<SharedMemory> unvalidatedConvert(const hidl_memory& memory) {
+ return hal::utils::createSharedMemoryFromHidlMemory(memory);
}
GeneralResult<Model> unvalidatedConvert(const hal::V1_0::Model& model) {
@@ -346,9 +346,8 @@
return hidl_vec<uint8_t>(operandValues.data(), operandValues.data() + operandValues.size());
}
-nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::Memory& memory) {
- return hidl_memory(memory.name, NN_TRY(hal::utils::hidlHandleFromSharedHandle(memory.handle)),
- memory.size);
+nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::SharedMemory& memory) {
+ return hal::utils::createHidlMemoryFromSharedMemory(memory);
}
nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model) {
@@ -392,7 +391,7 @@
}
nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::Request::MemoryPool& memoryPool) {
- return unvalidatedConvert(std::get<nn::Memory>(memoryPool));
+ return unvalidatedConvert(std::get<nn::SharedMemory>(memoryPool));
}
nn::GeneralResult<Request> unvalidatedConvert(const nn::Request& request) {
diff --git a/neuralnetworks/1.1/utils/src/Conversions.cpp b/neuralnetworks/1.1/utils/src/Conversions.cpp
index b47f25a..07bf7bc 100644
--- a/neuralnetworks/1.1/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.1/utils/src/Conversions.cpp
@@ -175,7 +175,7 @@
return V1_0::utils::unvalidatedConvert(operandValues);
}
-nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::Memory& memory) {
+nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::SharedMemory& memory) {
return V1_0::utils::unvalidatedConvert(memory);
}
diff --git a/neuralnetworks/1.2/utils/src/Conversions.cpp b/neuralnetworks/1.2/utils/src/Conversions.cpp
index 062f6f7..7ae483e 100644
--- a/neuralnetworks/1.2/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.2/utils/src/Conversions.cpp
@@ -304,7 +304,11 @@
}
GeneralResult<SharedHandle> unvalidatedConvert(const hidl_handle& hidlHandle) {
- return hal::utils::sharedHandleFromNativeHandle(hidlHandle.getNativeHandle());
+ if (hidlHandle.getNativeHandle() == nullptr) {
+ return nullptr;
+ }
+ auto handle = NN_TRY(hal::utils::sharedHandleFromNativeHandle(hidlHandle.getNativeHandle()));
+ return std::make_shared<const Handle>(std::move(handle));
}
GeneralResult<DeviceType> convert(const hal::V1_2::DeviceType& deviceType) {
@@ -365,7 +369,7 @@
return V1_0::utils::unvalidatedConvert(operandValues);
}
-nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::Memory& memory) {
+nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::SharedMemory& memory) {
return V1_0::utils::unvalidatedConvert(memory);
}
@@ -588,7 +592,10 @@
}
nn::GeneralResult<hidl_handle> unvalidatedConvert(const nn::SharedHandle& handle) {
- return hal::utils::hidlHandleFromSharedHandle(handle);
+ if (handle == nullptr) {
+ return {};
+ }
+ return hal::utils::hidlHandleFromSharedHandle(*handle);
}
nn::GeneralResult<DeviceType> convert(const nn::DeviceType& deviceType) {
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h
index fda79c8..69e87f7 100644
--- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h
@@ -42,8 +42,8 @@
nn::Request::MemoryDomainToken getToken() const override;
- nn::GeneralResult<void> copyTo(const nn::Memory& dst) const override;
- nn::GeneralResult<void> copyFrom(const nn::Memory& src,
+ nn::GeneralResult<void> copyTo(const nn::SharedMemory& dst) const override;
+ nn::GeneralResult<void> copyFrom(const nn::SharedMemory& src,
const nn::Dimensions& dimensions) const override;
private:
diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Conversions.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Conversions.h
index 74a6534..8e1cdb8 100644
--- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Conversions.h
+++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Conversions.h
@@ -59,7 +59,7 @@
GeneralResult<ErrorStatus> convert(const hal::V1_3::ErrorStatus& errorStatus);
GeneralResult<SharedHandle> convert(const hardware::hidl_handle& handle);
-GeneralResult<Memory> convert(const hardware::hidl_memory& memory);
+GeneralResult<SharedMemory> convert(const hardware::hidl_memory& memory);
GeneralResult<std::vector<BufferRole>> convert(
const hardware::hidl_vec<hal::V1_3::BufferRole>& bufferRoles);
@@ -100,7 +100,7 @@
nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& errorStatus);
nn::GeneralResult<hidl_handle> convert(const nn::SharedHandle& handle);
-nn::GeneralResult<hidl_memory> convert(const nn::Memory& memory);
+nn::GeneralResult<hidl_memory> convert(const nn::SharedMemory& memory);
nn::GeneralResult<hidl_vec<BufferRole>> convert(const std::vector<nn::BufferRole>& bufferRoles);
nn::GeneralResult<V1_0::DeviceStatus> convert(const nn::DeviceStatus& deviceStatus);
diff --git a/neuralnetworks/1.3/utils/src/Buffer.cpp b/neuralnetworks/1.3/utils/src/Buffer.cpp
index 614033e..ada5265 100644
--- a/neuralnetworks/1.3/utils/src/Buffer.cpp
+++ b/neuralnetworks/1.3/utils/src/Buffer.cpp
@@ -61,7 +61,7 @@
return kToken;
}
-nn::GeneralResult<void> Buffer::copyTo(const nn::Memory& dst) const {
+nn::GeneralResult<void> Buffer::copyTo(const nn::SharedMemory& dst) const {
const auto hidlDst = NN_TRY(convert(dst));
const auto ret = kBuffer->copyTo(hidlDst);
@@ -71,7 +71,7 @@
return {};
}
-nn::GeneralResult<void> Buffer::copyFrom(const nn::Memory& src,
+nn::GeneralResult<void> Buffer::copyFrom(const nn::SharedMemory& src,
const nn::Dimensions& dimensions) const {
const auto hidlSrc = NN_TRY(convert(src));
const auto hidlDimensions = hidl_vec<uint32_t>(dimensions);
diff --git a/neuralnetworks/1.3/utils/src/Conversions.cpp b/neuralnetworks/1.3/utils/src/Conversions.cpp
index 8b7db2b..6e74a62 100644
--- a/neuralnetworks/1.3/utils/src/Conversions.cpp
+++ b/neuralnetworks/1.3/utils/src/Conversions.cpp
@@ -261,7 +261,7 @@
using Discriminator = hal::V1_3::Request::MemoryPool::hidl_discriminator;
switch (memoryPool.getDiscriminator()) {
case Discriminator::hidlMemory:
- return createSharedMemoryFromHidlMemory(memoryPool.hidlMemory());
+ return hal::utils::createSharedMemoryFromHidlMemory(memoryPool.hidlMemory());
case Discriminator::token:
return static_cast<Request::MemoryDomainToken>(memoryPool.token());
}
@@ -352,7 +352,7 @@
return validatedConvert(handle);
}
-GeneralResult<Memory> convert(const hardware::hidl_memory& memory) {
+GeneralResult<SharedMemory> convert(const hardware::hidl_memory& memory) {
return validatedConvert(memory);
}
@@ -386,7 +386,7 @@
return V1_2::utils::unvalidatedConvert(handle);
}
-nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::Memory& memory) {
+nn::GeneralResult<hidl_memory> unvalidatedConvert(const nn::SharedMemory& memory) {
return V1_0::utils::unvalidatedConvert(memory);
}
@@ -424,7 +424,7 @@
return unvalidatedConvertVec(arguments);
}
-nn::GeneralResult<Request::MemoryPool> makeMemoryPool(const nn::Memory& memory) {
+nn::GeneralResult<Request::MemoryPool> makeMemoryPool(const nn::SharedMemory& memory) {
Request::MemoryPool ret;
ret.hidlMemory(NN_TRY(unvalidatedConvert(memory)));
return ret;
@@ -677,7 +677,7 @@
return validatedConvert(handle);
}
-nn::GeneralResult<hidl_memory> convert(const nn::Memory& memory) {
+nn::GeneralResult<hidl_memory> convert(const nn::SharedMemory& memory) {
return validatedConvert(memory);
}
diff --git a/neuralnetworks/aidl/utils/Android.bp b/neuralnetworks/aidl/utils/Android.bp
index 56017da..147d401 100644
--- a/neuralnetworks/aidl/utils/Android.bp
+++ b/neuralnetworks/aidl/utils/Android.bp
@@ -21,12 +21,14 @@
local_include_dirs: ["include/nnapi/hal/aidl/"],
export_include_dirs: ["include"],
static_libs: [
+ "libarect",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
],
shared_libs: [
- "libhidlbase",
"android.hardware.neuralnetworks-V1-ndk_platform",
"libbinder_ndk",
+ "libhidlbase",
+ "libnativewindow",
],
}
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
index 35de5be..1b2f69c 100644
--- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h
@@ -79,7 +79,7 @@
GeneralResult<Model::Subgraph> unvalidatedConvert(const aidl_hal::Subgraph& subgraph);
GeneralResult<OutputShape> unvalidatedConvert(const aidl_hal::OutputShape& outputShape);
GeneralResult<MeasureTiming> unvalidatedConvert(bool measureTiming);
-GeneralResult<Memory> unvalidatedConvert(const aidl_hal::Memory& memory);
+GeneralResult<SharedMemory> unvalidatedConvert(const aidl_hal::Memory& memory);
GeneralResult<Timing> unvalidatedConvert(const aidl_hal::Timing& timing);
GeneralResult<BufferDesc> unvalidatedConvert(const aidl_hal::BufferDesc& bufferDesc);
GeneralResult<BufferRole> unvalidatedConvert(const aidl_hal::BufferRole& bufferRole);
@@ -99,7 +99,7 @@
GeneralResult<ExecutionPreference> convert(
const aidl_hal::ExecutionPreference& executionPreference);
-GeneralResult<Memory> convert(const aidl_hal::Memory& memory);
+GeneralResult<SharedMemory> convert(const aidl_hal::Memory& memory);
GeneralResult<Model> convert(const aidl_hal::Model& model);
GeneralResult<Operand> convert(const aidl_hal::Operand& operand);
GeneralResult<OperandType> convert(const aidl_hal::OperandType& operandType);
@@ -108,7 +108,7 @@
GeneralResult<Request> convert(const aidl_hal::Request& request);
GeneralResult<std::vector<Operation>> convert(const std::vector<aidl_hal::Operation>& outputShapes);
-GeneralResult<std::vector<Memory>> convert(const std::vector<aidl_hal::Memory>& memories);
+GeneralResult<std::vector<SharedMemory>> convert(const std::vector<aidl_hal::Memory>& memories);
GeneralResult<std::vector<uint32_t>> toUnsigned(const std::vector<int32_t>& vec);
@@ -118,11 +118,11 @@
namespace nn = ::android::nn;
-nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory& memory);
+nn::GeneralResult<Memory> unvalidatedConvert(const nn::SharedMemory& memory);
nn::GeneralResult<OutputShape> unvalidatedConvert(const nn::OutputShape& outputShape);
nn::GeneralResult<ErrorStatus> unvalidatedConvert(const nn::ErrorStatus& errorStatus);
-nn::GeneralResult<Memory> convert(const nn::Memory& memory);
+nn::GeneralResult<Memory> convert(const nn::SharedMemory& memory);
nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& errorStatus);
nn::GeneralResult<std::vector<OutputShape>> convert(
const std::vector<nn::OutputShape>& outputShapes);
diff --git a/neuralnetworks/aidl/utils/src/Conversions.cpp b/neuralnetworks/aidl/utils/src/Conversions.cpp
index 0e93b02..db3504b 100644
--- a/neuralnetworks/aidl/utils/src/Conversions.cpp
+++ b/neuralnetworks/aidl/utils/src/Conversions.cpp
@@ -18,6 +18,8 @@
#include <aidl/android/hardware/common/NativeHandle.h>
#include <android-base/logging.h>
+#include <android/hardware_buffer.h>
+#include <cutils/native_handle.h>
#include <nnapi/OperandTypes.h>
#include <nnapi/OperationTypes.h>
#include <nnapi/Result.h>
@@ -27,6 +29,7 @@
#include <nnapi/Validation.h>
#include <nnapi/hal/CommonUtils.h>
#include <nnapi/hal/HandleError.h>
+#include <vndk/hardware_buffer.h>
#include <algorithm>
#include <chrono>
@@ -53,6 +56,8 @@
namespace android::nn {
namespace {
+using ::aidl::android::hardware::common::NativeHandle;
+
constexpr auto validOperandType(nn::OperandType operandType) {
switch (operandType) {
case nn::OperandType::FLOAT32:
@@ -125,6 +130,61 @@
return canonical;
}
+GeneralResult<Handle> unvalidatedConvertHelper(const NativeHandle& aidlNativeHandle) {
+ std::vector<base::unique_fd> fds;
+ fds.reserve(aidlNativeHandle.fds.size());
+ for (const auto& fd : aidlNativeHandle.fds) {
+ const int dupFd = dup(fd.get());
+ if (dupFd == -1) {
+ // TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return
+ // here?
+ return NN_ERROR() << "Failed to dup the fd";
+ }
+ fds.emplace_back(dupFd);
+ }
+
+ return Handle{.fds = std::move(fds), .ints = aidlNativeHandle.ints};
+}
+
+struct NativeHandleDeleter {
+ void operator()(native_handle_t* handle) const {
+ if (handle) {
+ native_handle_close(handle);
+ native_handle_delete(handle);
+ }
+ }
+};
+
+using UniqueNativeHandle = std::unique_ptr<native_handle_t, NativeHandleDeleter>;
+
+static nn::GeneralResult<UniqueNativeHandle> nativeHandleFromAidlHandle(
+ const NativeHandle& handle) {
+ std::vector<base::unique_fd> fds;
+ fds.reserve(handle.fds.size());
+ for (const auto& fd : handle.fds) {
+ const int dupFd = dup(fd.get());
+ if (dupFd == -1) {
+ return NN_ERROR() << "Failed to dup the fd";
+ }
+ fds.emplace_back(dupFd);
+ }
+
+ constexpr size_t kIntMax = std::numeric_limits<int>::max();
+ CHECK_LE(handle.fds.size(), kIntMax);
+ CHECK_LE(handle.ints.size(), kIntMax);
+ native_handle_t* nativeHandle = native_handle_create(static_cast<int>(handle.fds.size()),
+ static_cast<int>(handle.ints.size()));
+ if (nativeHandle == nullptr) {
+ return NN_ERROR() << "Failed to create native_handle";
+ }
+ for (size_t i = 0; i < fds.size(); ++i) {
+ nativeHandle->data[i] = fds[i].release();
+ }
+ std::copy(handle.ints.begin(), handle.ints.end(), &nativeHandle->data[nativeHandle->numFds]);
+
+ return UniqueNativeHandle(nativeHandle);
+}
+
} // anonymous namespace
GeneralResult<OperandType> unvalidatedConvert(const aidl_hal::OperandType& operandType) {
@@ -316,13 +376,67 @@
return measureTiming ? MeasureTiming::YES : MeasureTiming::NO;
}
-GeneralResult<Memory> unvalidatedConvert(const aidl_hal::Memory& memory) {
+static uint32_t roundUpToMultiple(uint32_t value, uint32_t multiple) {
+ return (value + multiple - 1) / multiple * multiple;
+}
+
+GeneralResult<SharedMemory> unvalidatedConvert(const aidl_hal::Memory& memory) {
VERIFY_NON_NEGATIVE(memory.size) << "Memory size must not be negative";
- return Memory{
- .handle = NN_TRY(unvalidatedConvert(memory.handle)),
+ if (memory.size > std::numeric_limits<uint32_t>::max()) {
+ return NN_ERROR() << "Memory: size must be <= std::numeric_limits<size_t>::max()";
+ }
+
+ if (memory.name != "hardware_buffer_blob") {
+ return std::make_shared<const Memory>(Memory{
+ .handle = NN_TRY(unvalidatedConvertHelper(memory.handle)),
+ .size = static_cast<uint32_t>(memory.size),
+ .name = memory.name,
+ });
+ }
+
+ const auto size = static_cast<uint32_t>(memory.size);
+ const auto format = AHARDWAREBUFFER_FORMAT_BLOB;
+ const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+ const uint32_t width = size;
+ const uint32_t height = 1; // height is always 1 for BLOB mode AHardwareBuffer.
+ const uint32_t layers = 1; // layers is always 1 for BLOB mode AHardwareBuffer.
+
+ const UniqueNativeHandle handle = NN_TRY(nativeHandleFromAidlHandle(memory.handle));
+ const native_handle_t* nativeHandle = handle.get();
+
+ // AHardwareBuffer_createFromHandle() might fail because an allocator
+ // expects a specific stride value. In that case, we try to guess it by
+ // aligning the width to small powers of 2.
+ // TODO(b/174120849): Avoid stride assumptions.
+ AHardwareBuffer* hardwareBuffer = nullptr;
+ status_t status = UNKNOWN_ERROR;
+ for (uint32_t alignment : {1, 4, 32, 64, 128, 2, 8, 16}) {
+ const uint32_t stride = roundUpToMultiple(width, alignment);
+ AHardwareBuffer_Desc desc{
+ .width = width,
+ .height = height,
+ .layers = layers,
+ .format = format,
+ .usage = usage,
+ .stride = stride,
+ };
+ status = AHardwareBuffer_createFromHandle(&desc, nativeHandle,
+ AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE,
+ &hardwareBuffer);
+ if (status == NO_ERROR) {
+ break;
+ }
+ }
+ if (status != NO_ERROR) {
+ return NN_ERROR(ErrorStatus::GENERAL_FAILURE)
+ << "Can't create AHardwareBuffer from handle. Error: " << status;
+ }
+
+ return std::make_shared<const Memory>(Memory{
+ .handle = HardwareBufferHandle(hardwareBuffer, /*takeOwnership=*/true),
.size = static_cast<uint32_t>(memory.size),
.name = memory.name,
- };
+ });
}
GeneralResult<Model::OperandValues> unvalidatedConvert(const std::vector<uint8_t>& operandValues) {
@@ -397,24 +511,8 @@
return static_cast<ExecutionPreference>(executionPreference);
}
-GeneralResult<SharedHandle> unvalidatedConvert(
- const ::aidl::android::hardware::common::NativeHandle& aidlNativeHandle) {
- std::vector<base::unique_fd> fds;
- fds.reserve(aidlNativeHandle.fds.size());
- for (const auto& fd : aidlNativeHandle.fds) {
- int dupFd = dup(fd.get());
- if (dupFd == -1) {
- // TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return
- // here?
- return NN_ERROR() << "Failed to dup the fd";
- }
- fds.emplace_back(dupFd);
- }
-
- return std::make_shared<const Handle>(Handle{
- .fds = std::move(fds),
- .ints = aidlNativeHandle.ints,
- });
+GeneralResult<SharedHandle> unvalidatedConvert(const NativeHandle& aidlNativeHandle) {
+ return std::make_shared<const Handle>(NN_TRY(unvalidatedConvertHelper(aidlNativeHandle)));
}
GeneralResult<ExecutionPreference> convert(
@@ -422,7 +520,7 @@
return validatedConvert(executionPreference);
}
-GeneralResult<Memory> convert(const aidl_hal::Memory& operand) {
+GeneralResult<SharedMemory> convert(const aidl_hal::Memory& operand) {
return validatedConvert(operand);
}
@@ -454,7 +552,7 @@
return unvalidatedConvert(operations);
}
-GeneralResult<std::vector<Memory>> convert(const std::vector<aidl_hal::Memory>& memories) {
+GeneralResult<std::vector<SharedMemory>> convert(const std::vector<aidl_hal::Memory>& memories) {
return validatedConvert(memories);
}
@@ -507,13 +605,11 @@
return halObject;
}
-} // namespace
-
-nn::GeneralResult<common::NativeHandle> unvalidatedConvert(const nn::SharedHandle& sharedHandle) {
+nn::GeneralResult<common::NativeHandle> unvalidatedConvert(const nn::Handle& handle) {
common::NativeHandle aidlNativeHandle;
- aidlNativeHandle.fds.reserve(sharedHandle->fds.size());
- for (const auto& fd : sharedHandle->fds) {
- int dupFd = dup(fd.get());
+ aidlNativeHandle.fds.reserve(handle.fds.size());
+ for (const auto& fd : handle.fds) {
+ const int dupFd = dup(fd.get());
if (dupFd == -1) {
// TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return
// here?
@@ -521,18 +617,71 @@
}
aidlNativeHandle.fds.emplace_back(dupFd);
}
- aidlNativeHandle.ints = sharedHandle->ints;
+ aidlNativeHandle.ints = handle.ints;
return aidlNativeHandle;
}
-nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory& memory) {
- if (memory.size > std::numeric_limits<int64_t>::max()) {
+static nn::GeneralResult<common::NativeHandle> aidlHandleFromNativeHandle(
+ const native_handle_t& handle) {
+ common::NativeHandle aidlNativeHandle;
+
+ aidlNativeHandle.fds.reserve(handle.numFds);
+ for (int i = 0; i < handle.numFds; ++i) {
+ const int dupFd = dup(handle.data[i]);
+ if (dupFd == -1) {
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd";
+ }
+ aidlNativeHandle.fds.emplace_back(dupFd);
+ }
+
+ aidlNativeHandle.ints = std::vector<int>(&handle.data[handle.numFds],
+ &handle.data[handle.numFds + handle.numInts]);
+
+ return aidlNativeHandle;
+}
+
+} // namespace
+
+nn::GeneralResult<common::NativeHandle> unvalidatedConvert(const nn::SharedHandle& sharedHandle) {
+ CHECK(sharedHandle != nullptr);
+ return unvalidatedConvert(*sharedHandle);
+}
+
+nn::GeneralResult<Memory> unvalidatedConvert(const nn::SharedMemory& memory) {
+ CHECK(memory != nullptr);
+ if (memory->size > std::numeric_limits<int64_t>::max()) {
return NN_ERROR() << "Memory size doesn't fit into int64_t.";
}
+ if (const auto* handle = std::get_if<nn::Handle>(&memory->handle)) {
+ return Memory{
+ .handle = NN_TRY(unvalidatedConvert(*handle)),
+ .size = static_cast<int64_t>(memory->size),
+ .name = memory->name,
+ };
+ }
+
+ const auto* ahwb = std::get<nn::HardwareBufferHandle>(memory->handle).get();
+ AHardwareBuffer_Desc bufferDesc;
+ AHardwareBuffer_describe(ahwb, &bufferDesc);
+
+ if (bufferDesc.format == AHARDWAREBUFFER_FORMAT_BLOB) {
+ CHECK_EQ(memory->size, bufferDesc.width);
+ CHECK_EQ(memory->name, "hardware_buffer_blob");
+ } else {
+ CHECK_EQ(memory->size, 0u);
+ CHECK_EQ(memory->name, "hardware_buffer");
+ }
+
+ const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(ahwb);
+ if (nativeHandle == nullptr) {
+ return NN_ERROR() << "unvalidatedConvert failed because AHardwareBuffer_getNativeHandle "
+ "returned nullptr";
+ }
+
return Memory{
- .handle = NN_TRY(unvalidatedConvert(memory.handle)),
- .size = static_cast<int64_t>(memory.size),
- .name = memory.name,
+ .handle = NN_TRY(aidlHandleFromNativeHandle(*nativeHandle)),
+ .size = static_cast<int64_t>(memory->size),
+ .name = memory->name,
};
}
@@ -558,7 +707,7 @@
.isSufficient = outputShape.isSufficient};
}
-nn::GeneralResult<Memory> convert(const nn::Memory& memory) {
+nn::GeneralResult<Memory> convert(const nn::SharedMemory& memory) {
return validatedConvert(memory);
}
diff --git a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
index 86d5f3f..4beb828 100644
--- a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
+++ b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp
@@ -266,7 +266,7 @@
copyTestBuffers(constCopies, operandValues.data());
// Shared memory.
- std::vector<nn::Memory> pools = {};
+ std::vector<nn::SharedMemory> pools = {};
if (constRefSize > 0) {
const auto pool = nn::createSharedMemory(constRefSize).value();
pools.push_back(pool);
diff --git a/neuralnetworks/aidl/vts/functional/Utils.cpp b/neuralnetworks/aidl/vts/functional/Utils.cpp
index 14a496a..3c7f5f7 100644
--- a/neuralnetworks/aidl/vts/functional/Utils.cpp
+++ b/neuralnetworks/aidl/vts/functional/Utils.cpp
@@ -135,7 +135,8 @@
ASSERT_EQ(AHardwareBuffer_allocate(&desc, &mAhwb), 0);
ASSERT_NE(mAhwb, nullptr);
- const auto sharedMemory = nn::createSharedMemoryFromAHWB(*mAhwb).value();
+ const auto sharedMemory =
+ nn::createSharedMemoryFromAHWB(mAhwb, /*takeOwnership=*/false).value();
mMapping = nn::map(sharedMemory).value();
mPtr = static_cast<uint8_t*>(std::get<void*>(mMapping.pointer));
CHECK_NE(mPtr, nullptr);
diff --git a/neuralnetworks/utils/common/Android.bp b/neuralnetworks/utils/common/Android.bp
index 6c491ae..50295f1 100644
--- a/neuralnetworks/utils/common/Android.bp
+++ b/neuralnetworks/utils/common/Android.bp
@@ -22,10 +22,12 @@
export_include_dirs: ["include"],
cflags: ["-Wthread-safety"],
static_libs: [
+ "libarect",
"neuralnetworks_types",
],
shared_libs: [
"libhidlbase",
+ "libnativewindow",
],
}
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h b/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h
index fef9d9c..547f203 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h
@@ -74,10 +74,12 @@
std::vector<uint32_t> countNumberOfConsumers(size_t numberOfOperands,
const std::vector<nn::Operation>& operations);
-nn::GeneralResult<nn::Memory> createSharedMemoryFromHidlMemory(const hidl_memory& memory);
+nn::GeneralResult<hidl_memory> createHidlMemoryFromSharedMemory(const nn::SharedMemory& memory);
+nn::GeneralResult<nn::SharedMemory> createSharedMemoryFromHidlMemory(const hidl_memory& memory);
-nn::GeneralResult<hidl_handle> hidlHandleFromSharedHandle(const nn::SharedHandle& handle);
-nn::GeneralResult<nn::SharedHandle> sharedHandleFromNativeHandle(const native_handle_t* handle);
+nn::GeneralResult<hidl_handle> hidlHandleFromSharedHandle(const nn::Handle& handle);
+nn::GeneralResult<nn::Handle> sharedHandleFromNativeHandle(const native_handle_t* handle);
+
nn::GeneralResult<hidl_vec<hidl_handle>> convertSyncFences(
const std::vector<nn::SyncFence>& fences);
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h b/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h
index 95a20a8..209b663 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h
@@ -14,6 +14,9 @@
* limitations under the License.
*/
+#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_HANDLE_ERROR_H
+#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_HANDLE_ERROR_H
+
#include <android/hidl/base/1.0/IBase.h>
#include <hidl/HidlSupport.h>
#include <nnapi/Result.h>
@@ -50,7 +53,8 @@
})
template <typename Type>
-nn::GeneralResult<Type> makeGeneralFailure(nn::Result<Type> result, nn::ErrorStatus status) {
+nn::GeneralResult<Type> makeGeneralFailure(
+ nn::Result<Type> result, nn::ErrorStatus status = nn::ErrorStatus::GENERAL_FAILURE) {
if (!result.has_value()) {
return nn::error(status) << std::move(result).error();
}
@@ -75,7 +79,8 @@
}
template <typename Type>
-nn::ExecutionResult<Type> makeExecutionFailure(nn::Result<Type> result, nn::ErrorStatus status) {
+nn::ExecutionResult<Type> makeExecutionFailure(
+ nn::Result<Type> result, nn::ErrorStatus status = nn::ErrorStatus::GENERAL_FAILURE) {
return makeExecutionFailure(makeGeneralFailure(result, status));
}
@@ -86,4 +91,6 @@
} else \
return NN_ERROR(canonical)
-} // namespace android::hardware::neuralnetworks::utils
\ No newline at end of file
+} // namespace android::hardware::neuralnetworks::utils
+
+#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_HANDLE_ERROR_H
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBuffer.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBuffer.h
index 8c04b88..0e98c2e 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBuffer.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBuffer.h
@@ -31,9 +31,9 @@
public:
nn::Request::MemoryDomainToken getToken() const override;
- nn::GeneralResult<void> copyTo(const nn::Memory& dst) const override;
+ nn::GeneralResult<void> copyTo(const nn::SharedMemory& dst) const override;
- nn::GeneralResult<void> copyFrom(const nn::Memory& src,
+ nn::GeneralResult<void> copyFrom(const nn::SharedMemory& src,
const nn::Dimensions& dimensions) const override;
};
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h
index 83e60b6..996858c 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h
@@ -29,7 +29,7 @@
class InvalidBurst final : public nn::IBurst {
public:
- OptionalCacheHold cacheMemory(const nn::Memory& memory) const override;
+ OptionalCacheHold cacheMemory(const nn::SharedMemory& memory) const override;
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
const nn::Request& request, nn::MeasureTiming measure) const override;
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBuffer.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBuffer.h
index d2c2469..c8ca6f2 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBuffer.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBuffer.h
@@ -46,9 +46,9 @@
nn::Request::MemoryDomainToken getToken() const override;
- nn::GeneralResult<void> copyTo(const nn::Memory& dst) const override;
+ nn::GeneralResult<void> copyTo(const nn::SharedMemory& dst) const override;
- nn::GeneralResult<void> copyFrom(const nn::Memory& src,
+ nn::GeneralResult<void> copyFrom(const nn::SharedMemory& src,
const nn::Dimensions& dimensions) const override;
private:
diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h
index 0df287f..3b87330 100644
--- a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h
+++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h
@@ -44,7 +44,7 @@
nn::SharedBurst getBurst() const;
nn::GeneralResult<nn::SharedBurst> recover(const nn::IBurst* failingBurst) const;
- OptionalCacheHold cacheMemory(const nn::Memory& memory) const override;
+ OptionalCacheHold cacheMemory(const nn::SharedMemory& memory) const override;
nn::ExecutionResult<std::pair<std::vector<nn::OutputShape>, nn::Timing>> execute(
const nn::Request& request, nn::MeasureTiming measure) const override;
diff --git a/neuralnetworks/utils/common/src/CommonUtils.cpp b/neuralnetworks/utils/common/src/CommonUtils.cpp
index c04c8df..7a5035f 100644
--- a/neuralnetworks/utils/common/src/CommonUtils.cpp
+++ b/neuralnetworks/utils/common/src/CommonUtils.cpp
@@ -20,11 +20,14 @@
#include <android-base/logging.h>
#include <android-base/unique_fd.h>
+#include <android/hardware_buffer.h>
+#include <hidl/HidlSupport.h>
#include <nnapi/Result.h>
#include <nnapi/SharedMemory.h>
#include <nnapi/TypeUtils.h>
#include <nnapi/Types.h>
#include <nnapi/Validation.h>
+#include <vndk/hardware_buffer.h>
#include <algorithm>
#include <any>
@@ -203,13 +206,13 @@
nn::GeneralResult<void> unflushDataFromSharedToPointer(
const nn::Request& request, const std::optional<nn::Request>& maybeRequestInShared) {
if (!maybeRequestInShared.has_value() || maybeRequestInShared->pools.empty() ||
- !std::holds_alternative<nn::Memory>(maybeRequestInShared->pools.back())) {
+ !std::holds_alternative<nn::SharedMemory>(maybeRequestInShared->pools.back())) {
return {};
}
const auto& requestInShared = *maybeRequestInShared;
// Map the memory.
- const auto& outputMemory = std::get<nn::Memory>(requestInShared.pools.back());
+ const auto& outputMemory = std::get<nn::SharedMemory>(requestInShared.pools.back());
const auto [pointer, size, context] = NN_TRY(map(outputMemory));
const uint8_t* constantPointer =
std::visit([](const auto& o) { return static_cast<const uint8_t*>(o); }, pointer);
@@ -248,44 +251,128 @@
return nn::countNumberOfConsumers(numberOfOperands, operations);
}
-nn::GeneralResult<hidl_handle> hidlHandleFromSharedHandle(const nn::SharedHandle& handle) {
- if (handle == nullptr) {
- return {};
+nn::GeneralResult<hidl_memory> createHidlMemoryFromSharedMemory(const nn::SharedMemory& memory) {
+ if (memory == nullptr) {
+ return NN_ERROR() << "Memory must be non-empty";
+ }
+ if (const auto* handle = std::get_if<nn::Handle>(&memory->handle)) {
+ return hidl_memory(memory->name, NN_TRY(hidlHandleFromSharedHandle(*handle)), memory->size);
}
+ const auto* ahwb = std::get<nn::HardwareBufferHandle>(memory->handle).get();
+ AHardwareBuffer_Desc bufferDesc;
+ AHardwareBuffer_describe(ahwb, &bufferDesc);
+
+ if (bufferDesc.format == AHARDWAREBUFFER_FORMAT_BLOB) {
+ CHECK_EQ(memory->size, bufferDesc.width);
+ CHECK_EQ(memory->name, "hardware_buffer_blob");
+ } else {
+ CHECK_EQ(memory->size, 0u);
+ CHECK_EQ(memory->name, "hardware_buffer");
+ }
+
+ const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(ahwb);
+ const hidl_handle hidlHandle(nativeHandle);
+ hidl_handle handle(hidlHandle);
+
+ return hidl_memory(memory->name, std::move(handle), memory->size);
+}
+
+static uint32_t roundUpToMultiple(uint32_t value, uint32_t multiple) {
+ return (value + multiple - 1) / multiple * multiple;
+}
+
+nn::GeneralResult<nn::SharedMemory> createSharedMemoryFromHidlMemory(const hidl_memory& memory) {
+ CHECK_LE(memory.size(), std::numeric_limits<uint32_t>::max());
+
+ if (memory.name() != "hardware_buffer_blob") {
+ return std::make_shared<const nn::Memory>(nn::Memory{
+ .handle = NN_TRY(sharedHandleFromNativeHandle(memory.handle())),
+ .size = static_cast<uint32_t>(memory.size()),
+ .name = memory.name(),
+ });
+ }
+
+ const auto size = memory.size();
+ const auto format = AHARDWAREBUFFER_FORMAT_BLOB;
+ const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+ const uint32_t width = size;
+ const uint32_t height = 1; // height is always 1 for BLOB mode AHardwareBuffer.
+ const uint32_t layers = 1; // layers is always 1 for BLOB mode AHardwareBuffer.
+
+ // AHardwareBuffer_createFromHandle() might fail because an allocator
+ // expects a specific stride value. In that case, we try to guess it by
+ // aligning the width to small powers of 2.
+ // TODO(b/174120849): Avoid stride assumptions.
+ AHardwareBuffer* hardwareBuffer = nullptr;
+ status_t status = UNKNOWN_ERROR;
+ for (uint32_t alignment : {1, 4, 32, 64, 128, 2, 8, 16}) {
+ const uint32_t stride = roundUpToMultiple(width, alignment);
+ AHardwareBuffer_Desc desc{
+ .width = width,
+ .height = height,
+ .layers = layers,
+ .format = format,
+ .usage = usage,
+ .stride = stride,
+ };
+ status = AHardwareBuffer_createFromHandle(&desc, memory.handle(),
+ AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE,
+ &hardwareBuffer);
+ if (status == NO_ERROR) {
+ break;
+ }
+ }
+ if (status != NO_ERROR) {
+ return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
+ << "Can't create AHardwareBuffer from handle. Error: " << status;
+ }
+
+ return std::make_shared<const nn::Memory>(nn::Memory{
+ .handle = nn::HardwareBufferHandle(hardwareBuffer, /*takeOwnership=*/true),
+ .size = static_cast<uint32_t>(memory.size()),
+ .name = memory.name(),
+ });
+}
+
+nn::GeneralResult<hidl_handle> hidlHandleFromSharedHandle(const nn::Handle& handle) {
std::vector<base::unique_fd> fds;
- fds.reserve(handle->fds.size());
- for (const auto& fd : handle->fds) {
- int dupFd = dup(fd);
+ fds.reserve(handle.fds.size());
+ for (const auto& fd : handle.fds) {
+ const int dupFd = dup(fd);
if (dupFd == -1) {
return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd";
}
fds.emplace_back(dupFd);
}
- native_handle_t* nativeHandle = native_handle_create(handle->fds.size(), handle->ints.size());
+ constexpr size_t kIntMax = std::numeric_limits<int>::max();
+ CHECK_LE(handle.fds.size(), kIntMax);
+ CHECK_LE(handle.ints.size(), kIntMax);
+ native_handle_t* nativeHandle = native_handle_create(static_cast<int>(handle.fds.size()),
+ static_cast<int>(handle.ints.size()));
if (nativeHandle == nullptr) {
return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to create native_handle";
}
for (size_t i = 0; i < fds.size(); ++i) {
nativeHandle->data[i] = fds[i].release();
}
- std::copy(handle->ints.begin(), handle->ints.end(), &nativeHandle->data[nativeHandle->numFds]);
+ std::copy(handle.ints.begin(), handle.ints.end(), &nativeHandle->data[nativeHandle->numFds]);
hidl_handle hidlHandle;
hidlHandle.setTo(nativeHandle, /*shouldOwn=*/true);
return hidlHandle;
}
-nn::GeneralResult<nn::SharedHandle> sharedHandleFromNativeHandle(const native_handle_t* handle) {
+nn::GeneralResult<nn::Handle> sharedHandleFromNativeHandle(const native_handle_t* handle) {
if (handle == nullptr) {
- return nullptr;
+ return NN_ERROR() << "sharedHandleFromNativeHandle failed because handle is nullptr";
}
std::vector<base::unique_fd> fds;
fds.reserve(handle->numFds);
for (int i = 0; i < handle->numFds; ++i) {
- int dupFd = dup(handle->data[i]);
+ const int dupFd = dup(handle->data[i]);
if (dupFd == -1) {
return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd";
}
@@ -295,18 +382,18 @@
std::vector<int> ints(&handle->data[handle->numFds],
&handle->data[handle->numFds + handle->numInts]);
- return std::make_shared<const nn::Handle>(nn::Handle{
- .fds = std::move(fds),
- .ints = std::move(ints),
- });
+ return nn::Handle{.fds = std::move(fds), .ints = std::move(ints)};
}
nn::GeneralResult<hidl_vec<hidl_handle>> convertSyncFences(
const std::vector<nn::SyncFence>& syncFences) {
hidl_vec<hidl_handle> handles(syncFences.size());
for (size_t i = 0; i < syncFences.size(); ++i) {
- handles[i] =
- NN_TRY(hal::utils::hidlHandleFromSharedHandle(syncFences[i].getSharedHandle()));
+ const auto& handle = syncFences[i].getSharedHandle();
+ if (handle == nullptr) {
+ return NN_ERROR() << "convertSyncFences failed because sync fence is empty";
+ }
+ handles[i] = NN_TRY(hidlHandleFromSharedHandle(*handle));
}
return handles;
}
diff --git a/neuralnetworks/utils/common/src/InvalidBuffer.cpp b/neuralnetworks/utils/common/src/InvalidBuffer.cpp
index c6f75d7..e73001d 100644
--- a/neuralnetworks/utils/common/src/InvalidBuffer.cpp
+++ b/neuralnetworks/utils/common/src/InvalidBuffer.cpp
@@ -30,11 +30,11 @@
return nn::Request::MemoryDomainToken{};
}
-nn::GeneralResult<void> InvalidBuffer::copyTo(const nn::Memory& /*dst*/) const {
+nn::GeneralResult<void> InvalidBuffer::copyTo(const nn::SharedMemory& /*dst*/) const {
return NN_ERROR() << "InvalidBuffer";
}
-nn::GeneralResult<void> InvalidBuffer::copyFrom(const nn::Memory& /*src*/,
+nn::GeneralResult<void> InvalidBuffer::copyFrom(const nn::SharedMemory& /*src*/,
const nn::Dimensions& /*dimensions*/) const {
return NN_ERROR() << "InvalidBuffer";
}
diff --git a/neuralnetworks/utils/common/src/InvalidBurst.cpp b/neuralnetworks/utils/common/src/InvalidBurst.cpp
index 4ca6603..81ca18d 100644
--- a/neuralnetworks/utils/common/src/InvalidBurst.cpp
+++ b/neuralnetworks/utils/common/src/InvalidBurst.cpp
@@ -26,7 +26,8 @@
namespace android::hardware::neuralnetworks::utils {
-InvalidBurst::OptionalCacheHold InvalidBurst::cacheMemory(const nn::Memory& /*memory*/) const {
+InvalidBurst::OptionalCacheHold InvalidBurst::cacheMemory(
+ const nn::SharedMemory& /*memory*/) const {
return nullptr;
}
diff --git a/neuralnetworks/utils/common/src/ResilientBuffer.cpp b/neuralnetworks/utils/common/src/ResilientBuffer.cpp
index 47abbe2..1904375 100644
--- a/neuralnetworks/utils/common/src/ResilientBuffer.cpp
+++ b/neuralnetworks/utils/common/src/ResilientBuffer.cpp
@@ -99,12 +99,12 @@
return getBuffer()->getToken();
}
-nn::GeneralResult<void> ResilientBuffer::copyTo(const nn::Memory& dst) const {
+nn::GeneralResult<void> ResilientBuffer::copyTo(const nn::SharedMemory& dst) const {
const auto fn = [&dst](const nn::IBuffer& buffer) { return buffer.copyTo(dst); };
return protect(*this, fn);
}
-nn::GeneralResult<void> ResilientBuffer::copyFrom(const nn::Memory& src,
+nn::GeneralResult<void> ResilientBuffer::copyFrom(const nn::SharedMemory& src,
const nn::Dimensions& dimensions) const {
const auto fn = [&src, &dimensions](const nn::IBuffer& buffer) {
return buffer.copyFrom(src, dimensions);
diff --git a/neuralnetworks/utils/common/src/ResilientBurst.cpp b/neuralnetworks/utils/common/src/ResilientBurst.cpp
index 0d3cb33..5ca868b 100644
--- a/neuralnetworks/utils/common/src/ResilientBurst.cpp
+++ b/neuralnetworks/utils/common/src/ResilientBurst.cpp
@@ -94,7 +94,8 @@
return mBurst;
}
-ResilientBurst::OptionalCacheHold ResilientBurst::cacheMemory(const nn::Memory& memory) const {
+ResilientBurst::OptionalCacheHold ResilientBurst::cacheMemory(
+ const nn::SharedMemory& memory) const {
return getBurst()->cacheMemory(memory);
}
diff --git a/neuralnetworks/utils/common/test/MockBuffer.h b/neuralnetworks/utils/common/test/MockBuffer.h
index c5405fb..59d5700 100644
--- a/neuralnetworks/utils/common/test/MockBuffer.h
+++ b/neuralnetworks/utils/common/test/MockBuffer.h
@@ -27,9 +27,9 @@
class MockBuffer final : public IBuffer {
public:
MOCK_METHOD(Request::MemoryDomainToken, getToken, (), (const, override));
- MOCK_METHOD(GeneralResult<void>, copyTo, (const Memory& dst), (const, override));
- MOCK_METHOD(GeneralResult<void>, copyFrom, (const Memory& src, const Dimensions& dimensions),
- (const, override));
+ MOCK_METHOD(GeneralResult<void>, copyTo, (const SharedMemory& dst), (const, override));
+ MOCK_METHOD(GeneralResult<void>, copyFrom,
+ (const SharedMemory& src, const Dimensions& dimensions), (const, override));
};
} // namespace android::nn
diff --git a/neuralnetworks/utils/common/test/ResilientBufferTest.cpp b/neuralnetworks/utils/common/test/ResilientBufferTest.cpp
index deb9b7c..7afd020 100644
--- a/neuralnetworks/utils/common/test/ResilientBufferTest.cpp
+++ b/neuralnetworks/utils/common/test/ResilientBufferTest.cpp
@@ -15,9 +15,11 @@
*/
#include <gmock/gmock.h>
+#include <nnapi/SharedMemory.h>
#include <nnapi/TypeUtils.h>
#include <nnapi/Types.h>
#include <nnapi/hal/ResilientBuffer.h>
+#include <memory>
#include <tuple>
#include <utility>
#include "MockBuffer.h"
@@ -113,7 +115,8 @@
EXPECT_CALL(*mockBuffer, copyTo(_)).Times(1).WillOnce(Return(kNoError));
// run test
- const auto result = buffer->copyTo({});
+ const nn::SharedMemory memory = std::make_shared<const nn::Memory>();
+ const auto result = buffer->copyTo(memory);
// verify result
ASSERT_TRUE(result.has_value())
@@ -126,7 +129,8 @@
EXPECT_CALL(*mockBuffer, copyTo(_)).Times(1).WillOnce(kReturnGeneralFailure);
// run test
- const auto result = buffer->copyTo({});
+ const nn::SharedMemory memory = std::make_shared<const nn::Memory>();
+ const auto result = buffer->copyTo(memory);
// verify result
ASSERT_FALSE(result.has_value());
@@ -140,7 +144,8 @@
EXPECT_CALL(*mockBufferFactory, Call()).Times(1).WillOnce(kReturnGeneralFailure);
// run test
- const auto result = buffer->copyTo({});
+ const nn::SharedMemory memory = std::make_shared<const nn::Memory>();
+ const auto result = buffer->copyTo(memory);
// verify result
ASSERT_FALSE(result.has_value());
@@ -156,7 +161,8 @@
EXPECT_CALL(*mockBufferFactory, Call()).Times(1).WillOnce(Return(recoveredMockBuffer));
// run test
- const auto result = buffer->copyTo({});
+ const nn::SharedMemory memory = std::make_shared<const nn::Memory>();
+ const auto result = buffer->copyTo(memory);
// verify result
ASSERT_TRUE(result.has_value())
@@ -169,7 +175,8 @@
EXPECT_CALL(*mockBuffer, copyFrom(_, _)).Times(1).WillOnce(Return(kNoError));
// run test
- const auto result = buffer->copyFrom({}, {});
+ const nn::SharedMemory memory = std::make_shared<const nn::Memory>();
+ const auto result = buffer->copyFrom(memory, {});
// verify result
ASSERT_TRUE(result.has_value())
@@ -182,7 +189,8 @@
EXPECT_CALL(*mockBuffer, copyFrom(_, _)).Times(1).WillOnce(kReturnGeneralFailure);
// run test
- const auto result = buffer->copyFrom({}, {});
+ const nn::SharedMemory memory = std::make_shared<const nn::Memory>();
+ const auto result = buffer->copyFrom(memory, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -196,7 +204,8 @@
EXPECT_CALL(*mockBufferFactory, Call()).Times(1).WillOnce(kReturnGeneralFailure);
// run test
- const auto result = buffer->copyFrom({}, {});
+ const nn::SharedMemory memory = std::make_shared<const nn::Memory>();
+ const auto result = buffer->copyFrom(memory, {});
// verify result
ASSERT_FALSE(result.has_value());
@@ -212,7 +221,8 @@
EXPECT_CALL(*mockBufferFactory, Call()).Times(1).WillOnce(Return(recoveredMockBuffer));
// run test
- const auto result = buffer->copyFrom({}, {});
+ const nn::SharedMemory memory = std::make_shared<const nn::Memory>();
+ const auto result = buffer->copyFrom(memory, {});
// verify result
ASSERT_TRUE(result.has_value())
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumer.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumer.aidl
index c8d7645..cd9239e 100644
--- a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumer.aidl
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumer.aidl
@@ -35,6 +35,6 @@
parcelable EnergyConsumer {
int id;
int ordinal;
- android.hardware.power.stats.EnergyConsumerType type;
+ android.hardware.power.stats.EnergyConsumerType type = android.hardware.power.stats.EnergyConsumerType.OTHER;
@utf8InCpp String name;
}
diff --git a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl
index 7b05d2f..ce3e1f5 100644
--- a/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl
+++ b/power/stats/aidl/aidl_api/android.hardware.power.stats/current/android/hardware/power/stats/EnergyConsumerType.aidl
@@ -34,6 +34,10 @@
@VintfStability
enum EnergyConsumerType {
OTHER = 0,
- CPU_CLUSTER = 1,
- DISPLAY = 2,
+ BLUETOOTH = 1,
+ CPU_CLUSTER = 2,
+ DISPLAY = 3,
+ GNSS = 4,
+ MOBILE_RADIO = 5,
+ WIFI = 6,
}
diff --git a/power/stats/aidl/android/hardware/power/stats/EnergyConsumer.aidl b/power/stats/aidl/android/hardware/power/stats/EnergyConsumer.aidl
index 2ff1279..ec616f2 100644
--- a/power/stats/aidl/android/hardware/power/stats/EnergyConsumer.aidl
+++ b/power/stats/aidl/android/hardware/power/stats/EnergyConsumer.aidl
@@ -32,10 +32,10 @@
int ordinal;
/* Type of this EnergyConsumer */
- EnergyConsumerType type;
+ EnergyConsumerType type = EnergyConsumerType.OTHER;
/**
* Unique name of this EnergyConsumer. Vendor/device specific. Opaque to framework
*/
@utf8InCpp String name;
-}
\ No newline at end of file
+}
diff --git a/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl b/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl
index 7fd2348..d871ced 100644
--- a/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl
+++ b/power/stats/aidl/android/hardware/power/stats/EnergyConsumerType.aidl
@@ -20,6 +20,10 @@
@VintfStability
enum EnergyConsumerType {
OTHER,
+ BLUETOOTH,
CPU_CLUSTER,
DISPLAY,
-}
\ No newline at end of file
+ GNSS,
+ MOBILE_RADIO,
+ WIFI,
+}
diff --git a/radio/1.6/IRadio.hal b/radio/1.6/IRadio.hal
index 7a13f0d..714be47 100644
--- a/radio/1.6/IRadio.hal
+++ b/radio/1.6/IRadio.hal
@@ -465,7 +465,7 @@
* cell information isn't known then the appropriate unknown value will be returned.
* This does not cause or change the rate of unsolicited cellInfoList().
*
- * This is identitcal to getCellInfoList in V1.0, but it requests updated version of CellInfo.
+ * This is identical to getCellInfoList in V1.0, but it requests updated version of CellInfo.
*
* @param serial Serial number of request.
*
diff --git a/radio/1.6/IRadioResponse.hal b/radio/1.6/IRadioResponse.hal
index 6ad5cf2..56ce809 100644
--- a/radio/1.6/IRadioResponse.hal
+++ b/radio/1.6/IRadioResponse.hal
@@ -19,6 +19,7 @@
import @1.0::SendSmsResult;
import @1.4::RadioAccessFamily;
import @1.5::IRadioResponse;
+import @1.5::RadioAccessSpecifier;
import @1.6::Call;
import @1.6::CellInfo;
import @1.6::RegStateResult;
@@ -344,6 +345,7 @@
/**
* @param info Response info struct containing response type, serial no. and error
+ * @param specifiers List of RadioAccessSpecifiers that are scanned.
*
* Valid errors returned:
* RadioError:NONE
@@ -351,7 +353,8 @@
* RadioError:INTERNAL_ERR
* RadioError:INVALID_ARGUMENTS
*/
- oneway getSystemSelectionChannelsResponse(RadioResponseInfo info);
+ oneway getSystemSelectionChannelsResponse(
+ RadioResponseInfo info, vec<RadioAccessSpecifier> specifiers);
/**
* This is identical to getCellInfoListResponse_1_5 but uses an updated version of CellInfo.
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
index f32e312..f610f2a 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
+++ b/radio/1.6/vts/functional/radio_hidl_hal_utils_v1_6.h
@@ -805,7 +805,8 @@
const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
Return<void> getSystemSelectionChannelsResponse(
- const ::android::hardware::radio::V1_6::RadioResponseInfo& info);
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+ const hidl_vec<::android::hardware::radio::V1_5::RadioAccessSpecifier>& specifier);
Return<void> getSignalStrengthResponse_1_6(
const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
diff --git a/radio/1.6/vts/functional/radio_response.cpp b/radio/1.6/vts/functional/radio_response.cpp
index fad3f12..027e9ac 100644
--- a/radio/1.6/vts/functional/radio_response.cpp
+++ b/radio/1.6/vts/functional/radio_response.cpp
@@ -1190,7 +1190,8 @@
}
Return<void> RadioResponse_v1_6::getSystemSelectionChannelsResponse(
- const ::android::hardware::radio::V1_6::RadioResponseInfo& info) {
+ const ::android::hardware::radio::V1_6::RadioResponseInfo& info,
+ const hidl_vec<::android::hardware::radio::V1_5::RadioAccessSpecifier>& /*specifier*/) {
rspInfo = info;
parent_v1_6.notify(info.serial);
return Void();
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/AttestationKey.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/AttestationKey.aidl
new file mode 100644
index 0000000..893b016
--- /dev/null
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/AttestationKey.aidl
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ *////////////////////////////////////////////////////////////////////////////////
+// THIS FILE IS IMMUTABLE. DO NOT EDIT IN ANY CASE. //
+///////////////////////////////////////////////////////////////////////////////
+
+// This file is a snapshot of an AIDL file. Do not edit it manually. There are
+// two cases:
+// 1). this is a frozen version file - do not edit this in any case.
+// 2). this is a 'current' file. If you make a backwards compatible change to
+// the interface (from the latest frozen version), the build system will
+// prompt you to update this file with `m <name>-update-api`.
+//
+// You must not make a backward incompatible change to any AIDL file built
+// with the aidl_interface module type with versions property set. The module
+// type is used to build AIDL files in a way that they can be used across
+// independently updatable components of the system. If a device is shipped
+// with such a backward incompatible change, it has a high risk of breaking
+// later when a module using the interface is updated, e.g., Mainline modules.
+
+package android.hardware.security.keymint;
+@RustDerive(Clone=true, Eq=true, Hash=true, Ord=true, PartialEq=true, PartialOrd=true) @VintfStability
+parcelable AttestationKey {
+ byte[] keyBlob;
+ android.hardware.security.keymint.KeyParameter[] attestKeyParams;
+ byte[] issuerSubjectName;
+}
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
index a35b46c..3faba48 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/ErrorCode.aidl
@@ -113,6 +113,8 @@
UNSUPPORTED_MGF_DIGEST = -79,
MISSING_NOT_BEFORE = -80,
MISSING_NOT_AFTER = -81,
+ MISSING_ISSUER_SUBJECT = -82,
+ INVALID_ISSUER_SUBJECT = -83,
UNIMPLEMENTED = -100,
VERSION_MISMATCH = -101,
UNKNOWN_ERROR = -1000,
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
index 9f4e509..d3c6910 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -35,14 +35,14 @@
interface IKeyMintDevice {
android.hardware.security.keymint.KeyMintHardwareInfo getHardwareInfo();
void addRngEntropy(in byte[] data);
- android.hardware.security.keymint.KeyCreationResult generateKey(in android.hardware.security.keymint.KeyParameter[] keyParams);
- android.hardware.security.keymint.KeyCreationResult importKey(in android.hardware.security.keymint.KeyParameter[] keyParams, in android.hardware.security.keymint.KeyFormat keyFormat, in byte[] keyData);
+ android.hardware.security.keymint.KeyCreationResult generateKey(in android.hardware.security.keymint.KeyParameter[] keyParams, in @nullable android.hardware.security.keymint.AttestationKey attestationKey);
+ android.hardware.security.keymint.KeyCreationResult importKey(in android.hardware.security.keymint.KeyParameter[] keyParams, in android.hardware.security.keymint.KeyFormat keyFormat, in byte[] keyData, in @nullable android.hardware.security.keymint.AttestationKey attestationKey);
android.hardware.security.keymint.KeyCreationResult importWrappedKey(in byte[] wrappedKeyData, in byte[] wrappingKeyBlob, in byte[] maskingKey, in android.hardware.security.keymint.KeyParameter[] unwrappingParams, in long passwordSid, in long biometricSid);
- byte[] upgradeKey(in byte[] inKeyBlobToUpgrade, in android.hardware.security.keymint.KeyParameter[] inUpgradeParams);
- void deleteKey(in byte[] inKeyBlob);
+ byte[] upgradeKey(in byte[] keyBlobToUpgrade, in android.hardware.security.keymint.KeyParameter[] upgradeParams);
+ void deleteKey(in byte[] keyBlob);
void deleteAllKeys();
void destroyAttestationIds();
- android.hardware.security.keymint.BeginResult begin(in android.hardware.security.keymint.KeyPurpose inPurpose, in byte[] inKeyBlob, in android.hardware.security.keymint.KeyParameter[] inParams, in android.hardware.security.keymint.HardwareAuthToken inAuthToken);
+ android.hardware.security.keymint.BeginResult begin(in android.hardware.security.keymint.KeyPurpose purpose, in byte[] keyBlob, in android.hardware.security.keymint.KeyParameter[] params, in android.hardware.security.keymint.HardwareAuthToken authToken);
void deviceLocked(in boolean passwordOnly, in @nullable android.hardware.security.secureclock.TimeStampToken timestampToken);
void earlyBootEnded();
const int AUTH_TOKEN_MAC_LENGTH = 32;
diff --git a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl
index c1e92af..61bb7e4 100644
--- a/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl
+++ b/security/keymint/aidl/aidl_api/android.hardware.security.keymint/current/android/hardware/security/keymint/KeyPurpose.aidl
@@ -39,4 +39,5 @@
VERIFY = 3,
WRAP_KEY = 5,
AGREE_KEY = 6,
+ ATTEST_KEY = 7,
}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/AttestationKey.aidl b/security/keymint/aidl/android/hardware/security/keymint/AttestationKey.aidl
new file mode 100644
index 0000000..8167ceb
--- /dev/null
+++ b/security/keymint/aidl/android/hardware/security/keymint/AttestationKey.aidl
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+package android.hardware.security.keymint;
+
+import android.hardware.security.keymint.KeyParameter;
+
+/**
+ * Contains a key blob with Tag::ATTEST_KEY that can be used to sign an attestation certificate,
+ * and the DER-encoded X.501 Subject Name that will be placed in the Issuer field of the attestation
+ * certificate.
+ */
+@VintfStability
+@RustDerive(Clone=true, Eq=true, PartialEq=true, Ord=true, PartialOrd=true, Hash=true)
+parcelable AttestationKey {
+ byte[] keyBlob;
+ KeyParameter[] attestKeyParams;
+ byte[] issuerSubjectName;
+}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl b/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
index 35e3827..5765130 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/ErrorCode.aidl
@@ -103,6 +103,8 @@
UNSUPPORTED_MGF_DIGEST = -79,
MISSING_NOT_BEFORE = -80,
MISSING_NOT_AFTER = -81,
+ MISSING_ISSUER_SUBJECT = -82,
+ INVALID_ISSUER_SUBJECT = -83,
UNIMPLEMENTED = -100,
VERSION_MISMATCH = -101,
diff --git a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
index 71abedd..13e98af 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/IKeyMintDevice.aidl
@@ -16,6 +16,7 @@
package android.hardware.security.keymint;
+import android.hardware.security.keymint.AttestationKey;
import android.hardware.security.keymint.BeginResult;
import android.hardware.security.keymint.ByteArray;
import android.hardware.security.keymint.HardwareAuthToken;
@@ -315,9 +316,18 @@
* provided in params. See above for detailed specifications of which tags are required
* for which types of keys.
*
+ * @param attestationKey, if provided, specifies the key that must be used to sign the
+ * attestation certificate. If `keyParams` does not contain a Tag::ATTESTATION_CHALLENGE
+ * but `attestationKey` is non-null, the IKeyMintDevice must return
+ * ErrorCode::INVALID_ARGUMENT. If the provided AttestationKey does not contain a key
+ * blob containing an asymmetric key with KeyPurpose::ATTEST_KEY, the IKeyMintDevice must
+ * return ErrorCode::INVALID_PURPOSE. If the provided AttestationKey has an empty issuer
+ * subject name, the IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
+ *
* @return The result of key creation. See KeyCreationResult.aidl.
*/
- KeyCreationResult generateKey(in KeyParameter[] keyParams);
+ KeyCreationResult generateKey(
+ in KeyParameter[] keyParams, in @nullable AttestationKey attestationKey);
/**
* Imports key material into an IKeyMintDevice. Key definition parameters and return values
@@ -345,10 +355,18 @@
*
* @param inKeyData The key material to import, in the format specified in keyFormat.
*
+ * @param attestationKey, if provided, specifies the key that must be used to sign the
+ * attestation certificate. If `keyParams` does not contain a Tag::ATTESTATION_CHALLENGE
+ * but `attestationKey` is non-null, the IKeyMintDevice must return
+ * ErrorCode::INVALID_ARGUMENT. If the provided AttestationKey does not contain a key
+ * blob containing an asymmetric key with KeyPurpose::ATTEST_KEY, the IKeyMintDevice must
+ * return ErrorCode::INVALID_PURPOSE. If the provided AttestationKey has an empty issuer
+ * subject name, the IKeyMintDevice must return ErrorCode::INVALID_ARGUMENT.
+ *
* @return The result of key creation. See KeyCreationResult.aidl.
*/
- KeyCreationResult importKey(
- in KeyParameter[] keyParams, in KeyFormat keyFormat, in byte[] keyData);
+ KeyCreationResult importKey(in KeyParameter[] keyParams, in KeyFormat keyFormat,
+ in byte[] keyData, in @nullable AttestationKey attestationKey);
/**
* Securely imports a key, or key pair, returning a key blob and a description of the imported
@@ -467,7 +485,7 @@
* @return A new key blob that references the same key as keyBlobToUpgrade, but is in the new
* format, or has the new version data.
*/
- byte[] upgradeKey(in byte[] inKeyBlobToUpgrade, in KeyParameter[] inUpgradeParams);
+ byte[] upgradeKey(in byte[] keyBlobToUpgrade, in KeyParameter[] upgradeParams);
/**
* Deletes the key, or key pair, associated with the key blob. Calling this function on
@@ -477,7 +495,7 @@
*
* @param inKeyBlob The opaque descriptor returned by generateKey() or importKey();
*/
- void deleteKey(in byte[] inKeyBlob);
+ void deleteKey(in byte[] keyBlob);
/**
* Deletes all keys in the hardware keystore. Used when keystore is reset completely. After
@@ -703,8 +721,8 @@
* from operations that generate an IV or nonce, and IKeyMintOperation object pointer
* which is used to perform update(), finish() or abort() operations.
*/
- BeginResult begin(in KeyPurpose inPurpose, in byte[] inKeyBlob, in KeyParameter[] inParams,
- in HardwareAuthToken inAuthToken);
+ BeginResult begin(in KeyPurpose purpose, in byte[] keyBlob, in KeyParameter[] params,
+ in HardwareAuthToken authToken);
/**
* Called by client to notify the IKeyMintDevice that the device is now locked, and keys with
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
index 68c1740..978a027 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyPurpose.aidl
@@ -16,12 +16,11 @@
package android.hardware.security.keymint;
-
/**
* Possible purposes of a key (or pair).
*/
@VintfStability
-@Backing(type = "int")
+@Backing(type="int")
enum KeyPurpose {
/* Usable with RSA, EC and AES keys. */
ENCRYPT = 0,
@@ -42,5 +41,7 @@
/* Key Agreement, usable with EC keys. */
AGREE_KEY = 6,
- /* TODO(seleneh) add ATTEST_KEY and their corresponding codes and tests later*/
+ /* Usable as an attestation signing key. Keys with this purpose must not have any other
+ * purpose. */
+ ATTEST_KEY = 7,
}
diff --git a/security/keymint/aidl/default/Android.bp b/security/keymint/aidl/default/Android.bp
index e9f3be0..e160548 100644
--- a/security/keymint/aidl/default/Android.bp
+++ b/security/keymint/aidl/default/Android.bp
@@ -14,8 +14,8 @@
],
shared_libs: [
"android.hardware.security.keymint-V1-ndk_platform",
- "android.hardware.security.sharedsecret-unstable-ndk_platform",
- "android.hardware.security.secureclock-unstable-ndk_platform",
+ "android.hardware.security.sharedsecret-V1-ndk_platform",
+ "android.hardware.security.secureclock-V1-ndk_platform",
"libbase",
"libbinder_ndk",
"libcppbor_external",
@@ -39,7 +39,7 @@
"libkeymint_remote_prov_support",
],
shared_libs: [
- "android.hardware.security.keymint-unstable-ndk_platform",
+ "android.hardware.security.keymint-V1-ndk_platform",
"libbinder_ndk",
"libcppbor_external",
"libcppcose",
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index 70f0b8a..24fe616 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -21,6 +21,7 @@
"use_libaidlvintf_gtest_helper_static",
],
srcs: [
+ "AttestKeyTest.cpp",
"KeyMintTest.cpp",
],
shared_libs: [
@@ -83,7 +84,7 @@
"libpuresoftkeymasterdevice",
],
static_libs: [
- "android.hardware.security.keymint-unstable-ndk_platform",
+ "android.hardware.security.keymint-V1-ndk_platform",
"libcppcose",
"libgmock_ndk",
"libremote_provisioner",
diff --git a/security/keymint/aidl/vts/functional/AttestKeyTest.cpp b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
new file mode 100644
index 0000000..7e7a466
--- /dev/null
+++ b/security/keymint/aidl/vts/functional/AttestKeyTest.cpp
@@ -0,0 +1,235 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "keymint_1_attest_key_test"
+#include <cutils/log.h>
+
+#include <keymint_support/key_param_output.h>
+#include <keymint_support/openssl_utils.h>
+
+#include "KeyMintAidlTestBase.h"
+
+namespace aidl::android::hardware::security::keymint::test {
+
+namespace {
+
+vector<uint8_t> make_name_from_str(const string& name) {
+ X509_NAME_Ptr x509_name(X509_NAME_new());
+ EXPECT_TRUE(x509_name.get() != nullptr);
+ if (!x509_name) return {};
+
+ EXPECT_EQ(1, X509_NAME_add_entry_by_txt(x509_name.get(), //
+ "CN", //
+ MBSTRING_ASC,
+ reinterpret_cast<const uint8_t*>(name.c_str()),
+ -1, // len
+ -1, // loc
+ 0 /* set */));
+
+ int len = i2d_X509_NAME(x509_name.get(), nullptr /* only return length */);
+ EXPECT_GT(len, 0);
+
+ vector<uint8_t> retval(len);
+ uint8_t* p = retval.data();
+ i2d_X509_NAME(x509_name.get(), &p);
+
+ return retval;
+}
+
+bool IsSelfSigned(const vector<Certificate>& chain) {
+ if (chain.size() != 1) return false;
+ return ChainSignaturesAreValid(chain);
+}
+
+} // namespace
+
+using AttestKeyTest = KeyMintAidlTestBase;
+
+TEST_P(AttestKeyTest, AllRsaSizes) {
+ for (auto size : ValidKeySizes(Algorithm::RSA)) {
+ /*
+ * Create attestaton key.
+ */
+ AttestationKey attest_key;
+ vector<KeyCharacteristics> attest_key_characteristics;
+ vector<Certificate> attest_key_cert_chain;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(size, 65537)
+ .AttestKey()
+ .SetDefaultValidity(),
+ {} /* attestation signing key */, &attest_key.keyBlob,
+ &attest_key_characteristics, &attest_key_cert_chain));
+
+ EXPECT_EQ(attest_key_cert_chain.size(), 1);
+ EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)) << "Failed on size " << size;
+
+ /*
+ * Use attestation key to sign RSA key
+ */
+ attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+ vector<uint8_t> attested_key_blob;
+ vector<KeyCharacteristics> attested_key_characteristics;
+ vector<Certificate> attested_key_cert_chain;
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .SetDefaultValidity(),
+ attest_key, &attested_key_blob, &attested_key_characteristics,
+ &attested_key_cert_chain));
+
+ CheckedDeleteKey(&attested_key_blob);
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+ EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+ attested_key_cert_chain[0].encodedCertificate));
+
+ // Attestation by itself is not valid (last entry is not self-signed).
+ EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+ if (attest_key_cert_chain.size() > 0) {
+ attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
+ }
+ EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ /*
+ * Use attestation key to sign EC key
+ */
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .SetDefaultValidity(),
+ attest_key, &attested_key_blob, &attested_key_characteristics,
+ &attested_key_cert_chain));
+
+ CheckedDeleteKey(&attested_key_blob);
+ CheckedDeleteKey(&attest_key.keyBlob);
+
+ hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+ EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+ attested_key_cert_chain[0].encodedCertificate));
+
+ // Attestation by itself is not valid (last entry is not self-signed).
+ EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+ if (attest_key_cert_chain.size() > 0) {
+ attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
+ }
+ EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ // Bail early if anything failed.
+ if (HasFailure()) return;
+ }
+}
+
+TEST_P(AttestKeyTest, AllEcCurves) {
+ for (auto curve : ValidCurves()) {
+ /*
+ * Create attestaton key.
+ */
+ AttestationKey attest_key;
+ vector<KeyCharacteristics> attest_key_characteristics;
+ vector<Certificate> attest_key_cert_chain;
+ ASSERT_EQ(ErrorCode::OK, GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(curve)
+ .AttestKey()
+ .SetDefaultValidity(),
+ {} /* attestation siging key */, &attest_key.keyBlob,
+ &attest_key_characteristics, &attest_key_cert_chain));
+
+ EXPECT_EQ(attest_key_cert_chain.size(), 1);
+ EXPECT_TRUE(IsSelfSigned(attest_key_cert_chain)) << "Failed on curve " << curve;
+
+ /*
+ * Use attestation key to sign RSA key
+ */
+ attest_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+ vector<uint8_t> attested_key_blob;
+ vector<KeyCharacteristics> attested_key_characteristics;
+ vector<Certificate> attested_key_cert_chain;
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(2048, 65537)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .SetDefaultValidity(),
+ attest_key, &attested_key_blob, &attested_key_characteristics,
+ &attested_key_cert_chain));
+
+ CheckedDeleteKey(&attested_key_blob);
+
+ AuthorizationSet hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ AuthorizationSet sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+ EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+ attested_key_cert_chain[0].encodedCertificate));
+
+ // Attestation by itself is not valid (last entry is not self-signed).
+ EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+ if (attest_key_cert_chain.size() > 0) {
+ attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
+ }
+ EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ /*
+ * Use attestation key to sign EC key
+ */
+ EXPECT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .EcdsaSigningKey(EcCurve::P_256)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .AttestationChallenge("foo")
+ .AttestationApplicationId("bar")
+ .SetDefaultValidity(),
+ attest_key, &attested_key_blob, &attested_key_characteristics,
+ &attested_key_cert_chain));
+
+ CheckedDeleteKey(&attested_key_blob);
+ CheckedDeleteKey(&attest_key.keyBlob);
+
+ hw_enforced = HwEnforcedAuthorizations(attested_key_characteristics);
+ sw_enforced = SwEnforcedAuthorizations(attested_key_characteristics);
+ EXPECT_TRUE(verify_attestation_record("foo", "bar", sw_enforced, hw_enforced, SecLevel(),
+ attested_key_cert_chain[0].encodedCertificate));
+
+ // Attestation by itself is not valid (last entry is not self-signed).
+ EXPECT_FALSE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ // Appending the attest_key chain to the attested_key_chain should yield a valid chain.
+ if (attest_key_cert_chain.size() > 0) {
+ attested_key_cert_chain.push_back(attest_key_cert_chain[0]);
+ }
+ EXPECT_TRUE(ChainSignaturesAreValid(attested_key_cert_chain));
+
+ // Bail early if anything failed.
+ if (HasFailure()) return;
+ }
+}
+
+INSTANTIATE_KEYMINT_AIDL_TEST(AttestKeyTest);
+
+} // namespace aidl::android::hardware::security::keymint::test
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index eb66aca..d61a081 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -22,15 +22,23 @@
#include <android-base/logging.h>
#include <android/binder_manager.h>
+#include <cutils/properties.h>
+#include <openssl/mem.h>
+#include <keymint_support/attestation_record.h>
#include <keymint_support/key_param_output.h>
#include <keymint_support/keymint_utils.h>
+#include <keymint_support/openssl_utils.h>
namespace aidl::android::hardware::security::keymint {
using namespace std::literals::chrono_literals;
using std::endl;
using std::optional;
+using std::unique_ptr;
+using ::testing::AssertionFailure;
+using ::testing::AssertionResult;
+using ::testing::AssertionSuccess;
::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set) {
if (set.size() == 0)
@@ -73,8 +81,67 @@
return true;
}
+// Extract attestation record from cert. Returned object is still part of cert; don't free it
+// separately.
+ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
+ ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
+ EXPECT_TRUE(!!oid.get());
+ if (!oid.get()) return nullptr;
+
+ int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
+ EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
+ if (location == -1) return nullptr;
+
+ X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
+ EXPECT_TRUE(!!attest_rec_ext)
+ << "Found attestation extension but couldn't retrieve it? Probably a BoringSSL bug.";
+ if (!attest_rec_ext) return nullptr;
+
+ ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
+ EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
+ return attest_rec;
+}
+
+bool avb_verification_enabled() {
+ char value[PROPERTY_VALUE_MAX];
+ return property_get("ro.boot.vbmeta.device_state", value, "") != 0;
+}
+
+char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
+
+// Attestations don't contain everything in key authorization lists, so we need to filter the key
+// lists to produce the lists that we expect to match the attestations.
+auto kTagsToFilter = {
+ Tag::BLOB_USAGE_REQUIREMENTS, //
+ Tag::CREATION_DATETIME, //
+ Tag::EC_CURVE,
+ Tag::HARDWARE_TYPE,
+ Tag::INCLUDE_UNIQUE_ID,
+};
+
+AuthorizationSet filtered_tags(const AuthorizationSet& set) {
+ AuthorizationSet filtered;
+ std::remove_copy_if(
+ set.begin(), set.end(), std::back_inserter(filtered), [](const auto& entry) -> bool {
+ return std::find(kTagsToFilter.begin(), kTagsToFilter.end(), entry.tag) !=
+ kTagsToFilter.end();
+ });
+ return filtered;
+}
+
+string x509NameToStr(X509_NAME* name) {
+ char* s = X509_NAME_oneline(name, nullptr, 0);
+ string retval(s);
+ OPENSSL_free(s);
+ return retval;
+}
+
} // namespace
+bool KeyMintAidlTestBase::arm_deleteAllKeys = false;
+bool KeyMintAidlTestBase::dump_Attestations = false;
+
ErrorCode KeyMintAidlTestBase::GetReturnErrorCode(const Status& result) {
if (result.isOk()) return ErrorCode::OK;
@@ -110,48 +177,48 @@
}
ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc,
+ const optional<AttestationKey>& attest_key,
vector<uint8_t>* key_blob,
- vector<KeyCharacteristics>* key_characteristics) {
+ vector<KeyCharacteristics>* key_characteristics,
+ vector<Certificate>* cert_chain) {
EXPECT_NE(key_blob, nullptr) << "Key blob pointer must not be null. Test bug";
EXPECT_NE(key_characteristics, nullptr)
<< "Previous characteristics not deleted before generating key. Test bug.";
- // Aidl does not clear these output parameters if the function returns
- // error. This is different from hal where output parameter is always
- // cleared due to hal returning void. So now we need to do our own clearing
- // of the output variables prior to calling keyMint aidl libraries.
- key_blob->clear();
- key_characteristics->clear();
- cert_chain_.clear();
-
KeyCreationResult creationResult;
- Status result = keymint_->generateKey(key_desc.vector_data(), &creationResult);
-
+ Status result = keymint_->generateKey(key_desc.vector_data(), attest_key, &creationResult);
if (result.isOk()) {
EXPECT_PRED2(KeyCharacteristicsBasicallyValid, SecLevel(),
creationResult.keyCharacteristics);
EXPECT_GT(creationResult.keyBlob.size(), 0);
*key_blob = std::move(creationResult.keyBlob);
*key_characteristics = std::move(creationResult.keyCharacteristics);
- cert_chain_ = std::move(creationResult.certificateChain);
+ *cert_chain = std::move(creationResult.certificateChain);
auto algorithm = key_desc.GetTagValue(TAG_ALGORITHM);
EXPECT_TRUE(algorithm);
if (algorithm &&
(algorithm.value() == Algorithm::RSA || algorithm.value() == Algorithm::EC)) {
- EXPECT_GE(cert_chain_.size(), 1);
- if (key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) EXPECT_GT(cert_chain_.size(), 1);
+ EXPECT_GE(cert_chain->size(), 1);
+ if (key_desc.Contains(TAG_ATTESTATION_CHALLENGE)) {
+ if (attest_key) {
+ EXPECT_EQ(cert_chain->size(), 1);
+ } else {
+ EXPECT_GT(cert_chain->size(), 1);
+ }
+ }
} else {
// For symmetric keys there should be no certificates.
- EXPECT_EQ(cert_chain_.size(), 0);
+ EXPECT_EQ(cert_chain->size(), 0);
}
}
return GetReturnErrorCode(result);
}
-ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc) {
- return GenerateKey(key_desc, &key_blob_, &key_characteristics_);
+ErrorCode KeyMintAidlTestBase::GenerateKey(const AuthorizationSet& key_desc,
+ const optional<AttestationKey>& attest_key) {
+ return GenerateKey(key_desc, attest_key, &key_blob_, &key_characteristics_, &cert_chain_);
}
ErrorCode KeyMintAidlTestBase::ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
@@ -166,7 +233,7 @@
KeyCreationResult creationResult;
result = keymint_->importKey(key_desc.vector_data(), format,
vector<uint8_t>(key_material.begin(), key_material.end()),
- &creationResult);
+ {} /* attestationSigningKeyBlob */, &creationResult);
if (result.isOk()) {
EXPECT_PRED2(KeyCharacteristicsBasicallyValid, SecLevel(),
@@ -916,6 +983,240 @@
return result;
}
+bool verify_attestation_record(const string& challenge, //
+ const string& app_id, //
+ AuthorizationSet expected_sw_enforced, //
+ AuthorizationSet expected_hw_enforced, //
+ SecurityLevel security_level,
+ const vector<uint8_t>& attestation_cert) {
+ X509_Ptr cert(parse_cert_blob(attestation_cert));
+ EXPECT_TRUE(!!cert.get());
+ if (!cert.get()) return false;
+
+ ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
+ EXPECT_TRUE(!!attest_rec);
+ if (!attest_rec) return false;
+
+ AuthorizationSet att_sw_enforced;
+ AuthorizationSet att_hw_enforced;
+ uint32_t att_attestation_version;
+ uint32_t att_keymaster_version;
+ SecurityLevel att_attestation_security_level;
+ SecurityLevel att_keymaster_security_level;
+ vector<uint8_t> att_challenge;
+ vector<uint8_t> att_unique_id;
+ vector<uint8_t> att_app_id;
+
+ auto error = parse_attestation_record(attest_rec->data, //
+ attest_rec->length, //
+ &att_attestation_version, //
+ &att_attestation_security_level, //
+ &att_keymaster_version, //
+ &att_keymaster_security_level, //
+ &att_challenge, //
+ &att_sw_enforced, //
+ &att_hw_enforced, //
+ &att_unique_id);
+ EXPECT_EQ(ErrorCode::OK, error);
+ if (error != ErrorCode::OK) return false;
+
+ EXPECT_GE(att_attestation_version, 3U);
+
+ expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID,
+ vector<uint8_t>(app_id.begin(), app_id.end()));
+
+ EXPECT_GE(att_keymaster_version, 4U);
+ EXPECT_EQ(security_level, att_keymaster_security_level);
+ EXPECT_EQ(security_level, att_attestation_security_level);
+
+ EXPECT_EQ(challenge.length(), att_challenge.size());
+ EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
+
+ char property_value[PROPERTY_VALUE_MAX] = {};
+ // 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()) {
+ 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) {
+ std::string date =
+ std::to_string(att_hw_enforced[i].value.get<KeyParameterValue::dateTime>());
+ // strptime seems to require delimiters, but the tag value will
+ // be YYYYMMDD
+ date.insert(6, "-");
+ date.insert(4, "-");
+ EXPECT_EQ(date.size(), 10);
+ struct tm time;
+ strptime(date.c_str(), "%Y-%m-%d", &time);
+
+ // Day of the month (0-31)
+ EXPECT_GE(time.tm_mday, 0);
+ EXPECT_LT(time.tm_mday, 32);
+ // Months since Jan (0-11)
+ EXPECT_GE(time.tm_mon, 0);
+ EXPECT_LT(time.tm_mon, 12);
+ // Years since 1900
+ EXPECT_GT(time.tm_year, 110);
+ EXPECT_LT(time.tm_year, 200);
+ }
+ }
+ }
+
+ // Check to make sure boolean values are properly encoded. Presence of a boolean tag
+ // indicates true. A provided boolean tag that can be pulled back out of the certificate
+ // indicates correct encoding. No need to check if it's in both lists, since the
+ // AuthorizationSet compare below will handle mismatches of tags.
+ if (security_level == SecurityLevel::SOFTWARE) {
+ EXPECT_TRUE(expected_sw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+ } else {
+ EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
+ }
+
+ // Alternatively this checks the opposite - a false boolean tag (one that isn't provided in
+ // the authorization list during key generation) isn't being attested to in the certificate.
+ EXPECT_FALSE(expected_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+ EXPECT_FALSE(att_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+ EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+ EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
+
+ if (att_hw_enforced.Contains(TAG_ALGORITHM, Algorithm::EC)) {
+ // For ECDSA keys, either an EC_CURVE or a KEY_SIZE can be specified, but one must be.
+ EXPECT_TRUE(att_hw_enforced.Contains(TAG_EC_CURVE) ||
+ att_hw_enforced.Contains(TAG_KEY_SIZE));
+ }
+
+ // Test root of trust elements
+ vector<uint8_t> verified_boot_key;
+ VerifiedBoot verified_boot_state;
+ bool device_locked;
+ vector<uint8_t> verified_boot_hash;
+ error = parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key,
+ &verified_boot_state, &device_locked, &verified_boot_hash);
+ EXPECT_EQ(ErrorCode::OK, error);
+
+ if (avb_verification_enabled()) {
+ EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
+ string prop_string(property_value);
+ EXPECT_EQ(prop_string.size(), 64);
+ EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
+
+ EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
+ if (!strcmp(property_value, "unlocked")) {
+ EXPECT_FALSE(device_locked);
+ } else {
+ EXPECT_TRUE(device_locked);
+ }
+
+ // Check that the device is locked if not debuggable, e.g., user build
+ // images in CTS. For VTS, debuggable images are used to allow adb root
+ // and the device is unlocked.
+ if (!property_get_bool("ro.debuggable", false)) {
+ EXPECT_TRUE(device_locked);
+ } else {
+ EXPECT_FALSE(device_locked);
+ }
+ }
+
+ // Verified boot key should be all 0's if the boot state is not verified or self signed
+ std::string empty_boot_key(32, '\0');
+ std::string verified_boot_key_str((const char*)verified_boot_key.data(),
+ verified_boot_key.size());
+ EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
+ if (!strcmp(property_value, "green")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
+ EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ } else if (!strcmp(property_value, "yellow")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
+ EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ } else if (!strcmp(property_value, "orange")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
+ EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ } else if (!strcmp(property_value, "red")) {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
+ } else {
+ EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
+ EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
+ verified_boot_key.size()));
+ }
+
+ att_sw_enforced.Sort();
+ expected_sw_enforced.Sort();
+ auto a = filtered_tags(expected_sw_enforced);
+ auto b = filtered_tags(att_sw_enforced);
+ EXPECT_EQ(a, b);
+
+ att_hw_enforced.Sort();
+ expected_hw_enforced.Sort();
+ EXPECT_EQ(filtered_tags(expected_hw_enforced), filtered_tags(att_hw_enforced));
+
+ return true;
+}
+
+string bin2hex(const vector<uint8_t>& data) {
+ string retval;
+ retval.reserve(data.size() * 2 + 1);
+ for (uint8_t byte : data) {
+ retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
+ retval.push_back(nibble2hex[0x0F & byte]);
+ }
+ return retval;
+}
+
+AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain) {
+ std::stringstream cert_data;
+
+ for (size_t i = 0; i < chain.size(); ++i) {
+ cert_data << bin2hex(chain[i].encodedCertificate) << std::endl;
+
+ X509_Ptr key_cert(parse_cert_blob(chain[i].encodedCertificate));
+ X509_Ptr signing_cert;
+ if (i < chain.size() - 1) {
+ signing_cert = parse_cert_blob(chain[i + 1].encodedCertificate);
+ } else {
+ signing_cert = parse_cert_blob(chain[i].encodedCertificate);
+ }
+ if (!key_cert.get() || !signing_cert.get()) return AssertionFailure() << cert_data.str();
+
+ EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
+ if (!signing_pubkey.get()) return AssertionFailure() << cert_data.str();
+
+ if (!X509_verify(key_cert.get(), signing_pubkey.get())) {
+ return AssertionFailure()
+ << "Verification of certificate " << i << " failed "
+ << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL) << '\n'
+ << cert_data.str();
+ }
+
+ 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) {
+ return AssertionFailure() << "Cert " << i << " has wrong issuer.\n" << cert_data.str();
+ }
+
+ if (i == 0) {
+ string cert_sub = x509NameToStr(X509_get_subject_name(key_cert.get()));
+ if ("/CN=Android Keystore Key" != cert_sub) {
+ return AssertionFailure()
+ << "Leaf cert has wrong subject, should be CN=Android Keystore Key, was "
+ << cert_sub << '\n'
+ << cert_data.str();
+ }
+ }
+ }
+
+ if (KeyMintAidlTestBase::dump_Attestations) std::cout << cert_data.str();
+ return AssertionSuccess();
+}
+
+X509_Ptr parse_cert_blob(const vector<uint8_t>& blob) {
+ const uint8_t* p = blob.data();
+ return X509_Ptr(d2i_X509(nullptr /* allocate new */, &p, blob.size()));
+}
+
} // namespace test
} // namespace aidl::android::hardware::security::keymint
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
index 4e546ed..452d2b6 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -21,20 +21,27 @@
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
#include <gtest/gtest.h>
+#include <openssl/x509.h>
#include <aidl/android/hardware/security/keymint/ErrorCode.h>
#include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
#include <keymint_support/authorization_set.h>
+#include <keymint_support/openssl_utils.h>
namespace aidl::android::hardware::security::keymint {
::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set);
+inline bool operator==(const keymint::AuthorizationSet& a, const keymint::AuthorizationSet& b) {
+ return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
+}
+
namespace test {
using ::android::sp;
using Status = ::ndk::ScopedAStatus;
+using ::std::optional;
using ::std::shared_ptr;
using ::std::string;
using ::std::vector;
@@ -48,6 +55,9 @@
vector<KeyCharacteristics> characteristics;
};
+ static bool arm_deleteAllKeys;
+ static bool dump_Attestations;
+
void SetUp() override;
void TearDown() override {
if (key_blob_.size()) {
@@ -62,10 +72,19 @@
uint32_t os_patch_level() { return os_patch_level_; }
ErrorCode GetReturnErrorCode(const Status& result);
- ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob,
- vector<KeyCharacteristics>* key_characteristics);
- ErrorCode GenerateKey(const AuthorizationSet& key_desc);
+ ErrorCode GenerateKey(const AuthorizationSet& key_desc, vector<uint8_t>* key_blob,
+ vector<KeyCharacteristics>* key_characteristics) {
+ return GenerateKey(key_desc, std::nullopt /* attest_key */, key_blob, key_characteristics,
+ &cert_chain_);
+ }
+ ErrorCode GenerateKey(const AuthorizationSet& key_desc,
+ const optional<AttestationKey>& attest_key, vector<uint8_t>* key_blob,
+ vector<KeyCharacteristics>* key_characteristics,
+ vector<Certificate>* cert_chain);
+ ErrorCode GenerateKey(const AuthorizationSet& key_desc,
+ const optional<AttestationKey>& attest_key = std::nullopt);
+
ErrorCode ImportKey(const AuthorizationSet& key_desc, KeyFormat format,
const string& key_material, vector<uint8_t>* key_blob,
vector<KeyCharacteristics>* key_characteristics);
@@ -254,6 +273,16 @@
long challenge_;
};
+bool verify_attestation_record(const string& challenge, //
+ const string& app_id, //
+ AuthorizationSet expected_sw_enforced, //
+ AuthorizationSet expected_hw_enforced, //
+ SecurityLevel security_level,
+ const vector<uint8_t>& attestation_cert);
+string bin2hex(const vector<uint8_t>& data);
+X509_Ptr parse_cert_blob(const vector<uint8_t>& blob);
+::testing::AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain);
+
#define INSTANTIATE_KEYMINT_AIDL_TEST(name) \
INSTANTIATE_TEST_SUITE_P(PerInstance, name, \
testing::ValuesIn(KeyMintAidlTestBase::build_params()), \
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 7801ed1..71aae90 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -14,7 +14,7 @@
* limitations under the License.
*/
-#define LOG_TAG "keymint_5_test"
+#define LOG_TAG "keymint_1_test"
#include <cutils/log.h>
#include <signal.h>
@@ -23,34 +23,21 @@
#include <openssl/ec.h>
#include <openssl/evp.h>
#include <openssl/mem.h>
-#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <cutils/properties.h>
#include <aidl/android/hardware/security/keymint/KeyFormat.h>
-#include <keymint_support/attestation_record.h>
#include <keymint_support/key_param_output.h>
#include <keymint_support/openssl_utils.h>
#include "KeyMintAidlTestBase.h"
-static bool arm_deleteAllKeys = false;
-static bool dump_Attestations = false;
-
using aidl::android::hardware::security::keymint::AuthorizationSet;
using aidl::android::hardware::security::keymint::KeyCharacteristics;
using aidl::android::hardware::security::keymint::KeyFormat;
-namespace aidl::android::hardware::security::keymint {
-
-bool operator==(const keymint::AuthorizationSet& a, const keymint::AuthorizationSet& b) {
- return a.size() == b.size() && std::equal(a.begin(), a.end(), b.begin());
-}
-
-} // namespace aidl::android::hardware::security::keymint
-
namespace std {
using namespace aidl::android::hardware::security::keymint;
@@ -183,281 +170,6 @@
void operator()(RSA* p) { RSA_free(p); }
};
-char nibble2hex[16] = {'0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
-
-string bin2hex(const vector<uint8_t>& data) {
- string retval;
- retval.reserve(data.size() * 2 + 1);
- for (uint8_t byte : data) {
- retval.push_back(nibble2hex[0x0F & (byte >> 4)]);
- retval.push_back(nibble2hex[0x0F & byte]);
- }
- return retval;
-}
-
-X509* parse_cert_blob(const vector<uint8_t>& blob) {
- const uint8_t* p = blob.data();
- return d2i_X509(nullptr, &p, blob.size());
-}
-
-bool verify_chain(const vector<Certificate>& chain) {
- for (size_t i = 0; i < chain.size(); ++i) {
- X509_Ptr key_cert(parse_cert_blob(chain[i].encodedCertificate));
- X509_Ptr signing_cert;
- if (i < chain.size() - 1) {
- signing_cert.reset(parse_cert_blob(chain[i + 1].encodedCertificate));
- } else {
- signing_cert.reset(parse_cert_blob(chain[i].encodedCertificate));
- }
- EXPECT_TRUE(!!key_cert.get() && !!signing_cert.get());
- if (!key_cert.get() || !signing_cert.get()) return false;
-
- EVP_PKEY_Ptr signing_pubkey(X509_get_pubkey(signing_cert.get()));
- EXPECT_TRUE(!!signing_pubkey.get());
- if (!signing_pubkey.get()) return false;
-
- EXPECT_EQ(1, X509_verify(key_cert.get(), signing_pubkey.get()))
- << "Verification of certificate " << i << " failed "
- << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
-
- char* cert_issuer = //
- X509_NAME_oneline(X509_get_issuer_name(key_cert.get()), nullptr, 0);
- char* signer_subj =
- X509_NAME_oneline(X509_get_subject_name(signing_cert.get()), nullptr, 0);
- EXPECT_STREQ(cert_issuer, signer_subj) << "Cert " << i << " has wrong issuer.";
- if (i == 0) {
- char* cert_sub = X509_NAME_oneline(X509_get_subject_name(key_cert.get()), nullptr, 0);
- EXPECT_STREQ("/CN=Android Keystore Key", cert_sub)
- << "Cert " << i << " has wrong subject.";
- OPENSSL_free(cert_sub);
- }
-
- OPENSSL_free(cert_issuer);
- OPENSSL_free(signer_subj);
-
- if (dump_Attestations) std::cout << bin2hex(chain[i].encodedCertificate) << std::endl;
- }
-
- return true;
-}
-
-// Extract attestation record from cert. Returned object is still part of cert; don't free it
-// separately.
-ASN1_OCTET_STRING* get_attestation_record(X509* certificate) {
- ASN1_OBJECT_Ptr oid(OBJ_txt2obj(kAttestionRecordOid, 1 /* dotted string format */));
- EXPECT_TRUE(!!oid.get());
- if (!oid.get()) return nullptr;
-
- int location = X509_get_ext_by_OBJ(certificate, oid.get(), -1 /* search from beginning */);
- EXPECT_NE(-1, location) << "Attestation extension not found in certificate";
- if (location == -1) return nullptr;
-
- X509_EXTENSION* attest_rec_ext = X509_get_ext(certificate, location);
- EXPECT_TRUE(!!attest_rec_ext)
- << "Found attestation extension but couldn't retrieve it? Probably a BoringSSL bug.";
- if (!attest_rec_ext) return nullptr;
-
- ASN1_OCTET_STRING* attest_rec = X509_EXTENSION_get_data(attest_rec_ext);
- EXPECT_TRUE(!!attest_rec) << "Attestation extension contained no data";
- return attest_rec;
-}
-
-bool tag_in_list(const KeyParameter& entry) {
- // Attestations don't contain everything in key authorization lists, so we need to filter
- // the key lists to produce the lists that we expect to match the attestations.
- auto tag_list = {
- Tag::BLOB_USAGE_REQUIREMENTS, //
- Tag::CREATION_DATETIME, //
- Tag::EC_CURVE,
- Tag::HARDWARE_TYPE,
- Tag::INCLUDE_UNIQUE_ID,
- };
- return std::find(tag_list.begin(), tag_list.end(), entry.tag) != tag_list.end();
-}
-
-AuthorizationSet filtered_tags(const AuthorizationSet& set) {
- AuthorizationSet filtered;
- std::remove_copy_if(set.begin(), set.end(), std::back_inserter(filtered), tag_in_list);
- return filtered;
-}
-
-bool avb_verification_enabled() {
- char value[PROPERTY_VALUE_MAX];
- return property_get("ro.boot.vbmeta.device_state", value, "") != 0;
-}
-
-bool verify_attestation_record(const string& challenge, //
- const string& app_id, //
- AuthorizationSet expected_sw_enforced, //
- AuthorizationSet expected_hw_enforced, //
- SecurityLevel security_level,
- const vector<uint8_t>& attestation_cert) {
- X509_Ptr cert(parse_cert_blob(attestation_cert));
- EXPECT_TRUE(!!cert.get());
- if (!cert.get()) return false;
-
- ASN1_OCTET_STRING* attest_rec = get_attestation_record(cert.get());
- EXPECT_TRUE(!!attest_rec);
- if (!attest_rec) return false;
-
- AuthorizationSet att_sw_enforced;
- AuthorizationSet att_hw_enforced;
- uint32_t att_attestation_version;
- uint32_t att_keymaster_version;
- SecurityLevel att_attestation_security_level;
- SecurityLevel att_keymaster_security_level;
- vector<uint8_t> att_challenge;
- vector<uint8_t> att_unique_id;
- vector<uint8_t> att_app_id;
-
- auto error = parse_attestation_record(attest_rec->data, //
- attest_rec->length, //
- &att_attestation_version, //
- &att_attestation_security_level, //
- &att_keymaster_version, //
- &att_keymaster_security_level, //
- &att_challenge, //
- &att_sw_enforced, //
- &att_hw_enforced, //
- &att_unique_id);
- EXPECT_EQ(ErrorCode::OK, error);
- if (error != ErrorCode::OK) return false;
-
- EXPECT_GE(att_attestation_version, 3U);
-
- expected_sw_enforced.push_back(TAG_ATTESTATION_APPLICATION_ID,
- vector<uint8_t>(app_id.begin(), app_id.end()));
-
- EXPECT_GE(att_keymaster_version, 4U);
- EXPECT_EQ(security_level, att_keymaster_security_level);
- EXPECT_EQ(security_level, att_attestation_security_level);
-
- EXPECT_EQ(challenge.length(), att_challenge.size());
- EXPECT_EQ(0, memcmp(challenge.data(), att_challenge.data(), challenge.length()));
-
- char property_value[PROPERTY_VALUE_MAX] = {};
- // 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()) {
- 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) {
- std::string date =
- std::to_string(att_hw_enforced[i].value.get<KeyParameterValue::dateTime>());
- // strptime seems to require delimiters, but the tag value will
- // be YYYYMMDD
- date.insert(6, "-");
- date.insert(4, "-");
- EXPECT_EQ(date.size(), 10);
- struct tm time;
- strptime(date.c_str(), "%Y-%m-%d", &time);
-
- // Day of the month (0-31)
- EXPECT_GE(time.tm_mday, 0);
- EXPECT_LT(time.tm_mday, 32);
- // Months since Jan (0-11)
- EXPECT_GE(time.tm_mon, 0);
- EXPECT_LT(time.tm_mon, 12);
- // Years since 1900
- EXPECT_GT(time.tm_year, 110);
- EXPECT_LT(time.tm_year, 200);
- }
- }
- }
-
- // Check to make sure boolean values are properly encoded. Presence of a boolean tag indicates
- // true. A provided boolean tag that can be pulled back out of the certificate indicates correct
- // encoding. No need to check if it's in both lists, since the AuthorizationSet compare below
- // will handle mismatches of tags.
- if (security_level == SecurityLevel::SOFTWARE) {
- EXPECT_TRUE(expected_sw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
- } else {
- EXPECT_TRUE(expected_hw_enforced.Contains(TAG_NO_AUTH_REQUIRED));
- }
-
- // Alternatively this checks the opposite - a false boolean tag (one that isn't provided in
- // the authorization list during key generation) isn't being attested to in the certificate.
- EXPECT_FALSE(expected_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
- EXPECT_FALSE(att_sw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
- EXPECT_FALSE(expected_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
- EXPECT_FALSE(att_hw_enforced.Contains(TAG_TRUSTED_USER_PRESENCE_REQUIRED));
-
- if (att_hw_enforced.Contains(TAG_ALGORITHM, Algorithm::EC)) {
- // For ECDSA keys, either an EC_CURVE or a KEY_SIZE can be specified, but one must be.
- EXPECT_TRUE(att_hw_enforced.Contains(TAG_EC_CURVE) ||
- att_hw_enforced.Contains(TAG_KEY_SIZE));
- }
-
- // Test root of trust elements
- vector<uint8_t> verified_boot_key;
- VerifiedBoot verified_boot_state;
- bool device_locked;
- vector<uint8_t> verified_boot_hash;
- error = parse_root_of_trust(attest_rec->data, attest_rec->length, &verified_boot_key,
- &verified_boot_state, &device_locked, &verified_boot_hash);
- EXPECT_EQ(ErrorCode::OK, error);
-
- if (avb_verification_enabled()) {
- EXPECT_NE(property_get("ro.boot.vbmeta.digest", property_value, ""), 0);
- string prop_string(property_value);
- EXPECT_EQ(prop_string.size(), 64);
- EXPECT_EQ(prop_string, bin2hex(verified_boot_hash));
-
- EXPECT_NE(property_get("ro.boot.vbmeta.device_state", property_value, ""), 0);
- if (!strcmp(property_value, "unlocked")) {
- EXPECT_FALSE(device_locked);
- } else {
- EXPECT_TRUE(device_locked);
- }
-
- // Check that the device is locked if not debuggable, e.g., user build
- // images in CTS. For VTS, debuggable images are used to allow adb root
- // and the device is unlocked.
- if (!property_get_bool("ro.debuggable", false)) {
- EXPECT_TRUE(device_locked);
- } else {
- EXPECT_FALSE(device_locked);
- }
- }
-
- // Verified boot key should be all 0's if the boot state is not verified or self signed
- std::string empty_boot_key(32, '\0');
- std::string verified_boot_key_str((const char*)verified_boot_key.data(),
- verified_boot_key.size());
- EXPECT_NE(property_get("ro.boot.verifiedbootstate", property_value, ""), 0);
- if (!strcmp(property_value, "green")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::VERIFIED);
- EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- } else if (!strcmp(property_value, "yellow")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::SELF_SIGNED);
- EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- } else if (!strcmp(property_value, "orange")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
- EXPECT_EQ(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- } else if (!strcmp(property_value, "red")) {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::FAILED);
- } else {
- EXPECT_EQ(verified_boot_state, VerifiedBoot::UNVERIFIED);
- EXPECT_NE(0, memcmp(verified_boot_key.data(), empty_boot_key.data(),
- verified_boot_key.size()));
- }
-
- att_sw_enforced.Sort();
- expected_sw_enforced.Sort();
- EXPECT_EQ(filtered_tags(expected_sw_enforced), filtered_tags(att_sw_enforced));
-
- att_hw_enforced.Sort();
- expected_hw_enforced.Sort();
- EXPECT_EQ(filtered_tags(expected_hw_enforced), filtered_tags(att_hw_enforced));
-
- return true;
-}
-
std::string make_string(const uint8_t* data, size_t length) {
return std::string(reinterpret_cast<const char*>(data), length);
}
@@ -596,7 +308,7 @@
<< "Key size " << key_size << "missing";
EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
- EXPECT_TRUE(verify_chain(cert_chain_));
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
ASSERT_GT(cert_chain_.size(), 0);
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
@@ -692,7 +404,7 @@
<< "key usage count limit " << 1U << " missing";
// Check the usage count limit tag also appears in the attestation.
- EXPECT_TRUE(verify_chain(cert_chain_));
+ EXPECT_TRUE(ChainSignaturesAreValid(cert_chain_));
ASSERT_GT(cert_chain_.size(), 0);
AuthorizationSet hw_enforced = HwEnforcedAuthorizations(key_characteristics);
@@ -5111,14 +4823,26 @@
} // namespace aidl::android::hardware::security::keymint::test
int main(int argc, char** argv) {
+ std::cout << "Testing ";
+ auto halInstances =
+ aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::build_params();
+ std::cout << "HAL instances:\n";
+ for (auto& entry : halInstances) {
+ std::cout << " " << entry << '\n';
+ }
+
::testing::InitGoogleTest(&argc, argv);
for (int i = 1; i < argc; ++i) {
if (argv[i][0] == '-') {
if (std::string(argv[i]) == "--arm_deleteAllKeys") {
- arm_deleteAllKeys = true;
+ aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::
+ arm_deleteAllKeys = true;
}
if (std::string(argv[i]) == "--dump_attestations") {
- dump_Attestations = true;
+ aidl::android::hardware::security::keymint::test::KeyMintAidlTestBase::
+ dump_Attestations = true;
+ } else {
+ std::cout << "NOT dumping attestations" << std::endl;
}
}
}
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index db53a8f..45f9df6 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -80,7 +80,7 @@
/**
* Generate and validate a production-mode key. MAC tag can't be verified.
*/
-TEST_P(GenerateKeyTests, generateEcdsaP256Key_prodMode) {
+TEST_P(GenerateKeyTests, DISABLED_generateEcdsaP256Key_prodMode) {
MacedPublicKey macedPubKey;
bytevec privateKeyBlob;
bool testMode = false;
@@ -133,7 +133,7 @@
/**
* Generate and validate a test-mode key.
*/
-TEST_P(GenerateKeyTests, generateEcdsaP256Key_testMode) {
+TEST_P(GenerateKeyTests, DISABLED_generateEcdsaP256Key_testMode) {
MacedPublicKey macedPubKey;
bytevec privateKeyBlob;
bool testMode = true;
@@ -224,7 +224,7 @@
* Generate an empty certificate request in test mode, and decrypt and verify the structure and
* content.
*/
-TEST_P(CertificateRequestTest, EmptyRequest_testMode) {
+TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_testMode) {
bool testMode = true;
bytevec keysToSignMac;
ProtectedData protectedData;
@@ -294,7 +294,7 @@
* TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
* able to decrypt.
*/
-TEST_P(CertificateRequestTest, EmptyRequest_prodMode) {
+TEST_P(CertificateRequestTest, DISABLED_EmptyRequest_prodMode) {
bool testMode = false;
bytevec keysToSignMac;
ProtectedData protectedData;
@@ -309,7 +309,7 @@
/**
* Generate a non-empty certificate request in test mode. Decrypt, parse and validate the contents.
*/
-TEST_P(CertificateRequestTest, NonEmptyRequest_testMode) {
+TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_testMode) {
bool testMode = true;
generateKeys(testMode, 4 /* numKeys */);
@@ -379,7 +379,7 @@
* TODO(swillden): Get a valid GEEK and use it so the generation can succeed, though we won't be
* able to decrypt.
*/
-TEST_P(CertificateRequestTest, NonEmptyRequest_prodMode) {
+TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodMode) {
bool testMode = false;
generateKeys(testMode, 4 /* numKeys */);
@@ -396,7 +396,7 @@
* Generate a non-empty certificate request in test mode, with prod keys. Must fail with
* STATUS_PRODUCTION_KEY_IN_TEST_REQUEST.
*/
-TEST_P(CertificateRequestTest, NonEmptyRequest_prodKeyInTestCert) {
+TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_prodKeyInTestCert) {
generateKeys(false /* testMode */, 2 /* numKeys */);
bytevec keysToSignMac;
@@ -414,7 +414,7 @@
* Generate a non-empty certificate request in prod mode, with test keys. Must fail with
* STATUS_TEST_KEY_IN_PRODUCTION_REQUEST.
*/
-TEST_P(CertificateRequestTest, NonEmptyRequest_testKeyInProdCert) {
+TEST_P(CertificateRequestTest, DISABLED_NonEmptyRequest_testKeyInProdCert) {
generateKeys(true /* testMode */, 2 /* numKeys */);
bytevec keysToSignMac;
diff --git a/security/keymint/aidl/vts/performance/Android.bp b/security/keymint/aidl/vts/performance/Android.bp
new file mode 100644
index 0000000..03240c3
--- /dev/null
+++ b/security/keymint/aidl/vts/performance/Android.bp
@@ -0,0 +1,38 @@
+//
+// 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.
+//
+
+cc_benchmark {
+ name: "VtsAidlKeyMintBenchmarkTest",
+ defaults: [
+ "VtsHalTargetTestDefaults",
+ "use_libaidlvintf_gtest_helper_static",
+ ],
+ srcs: [
+ "KeyMintBenchmark.cpp",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libcrypto",
+ "libkeymint",
+ "libkeymint_support",
+ ],
+ static_libs: [
+ "android.hardware.security.keymint-V1-ndk_platform",
+ "android.hardware.security.secureclock-V1-ndk_platform",
+ "libcppbor_external",
+ "libchrome",
+ ],
+}
diff --git a/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
new file mode 100644
index 0000000..f87ca78
--- /dev/null
+++ b/security/keymint/aidl/vts/performance/KeyMintBenchmark.cpp
@@ -0,0 +1,714 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "keymint_benchmark"
+
+#include <base/command_line.h>
+#include <benchmark/benchmark.h>
+#include <iostream>
+
+#include <aidl/Vintf.h>
+#include <aidl/android/hardware/security/keymint/ErrorCode.h>
+#include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
+#include <android/binder_manager.h>
+#include <binder/IServiceManager.h>
+#include <keymint_support/authorization_set.h>
+
+#define SMALL_MESSAGE_SIZE 64
+#define MEDIUM_MESSAGE_SIZE 1024
+#define LARGE_MESSAGE_SIZE 131072
+
+namespace aidl::android::hardware::security::keymint::test {
+
+::std::ostream& operator<<(::std::ostream& os, const keymint::AuthorizationSet& set);
+
+using ::android::sp;
+using Status = ::ndk::ScopedAStatus;
+using ::std::optional;
+using ::std::shared_ptr;
+using ::std::string;
+using ::std::vector;
+
+class KeyMintBenchmarkTest {
+ public:
+ KeyMintBenchmarkTest() {
+ message_cache_.push_back(string(SMALL_MESSAGE_SIZE, 'x'));
+ message_cache_.push_back(string(MEDIUM_MESSAGE_SIZE, 'x'));
+ message_cache_.push_back(string(LARGE_MESSAGE_SIZE, 'x'));
+ }
+
+ static KeyMintBenchmarkTest* newInstance(const char* instanceName) {
+ if (AServiceManager_isDeclared(instanceName)) {
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService(instanceName));
+ KeyMintBenchmarkTest* test = new KeyMintBenchmarkTest();
+ test->InitializeKeyMint(IKeyMintDevice::fromBinder(binder));
+ return test;
+ } else {
+ return nullptr;
+ }
+ }
+
+ int getError() { return static_cast<int>(error_); }
+
+ const string& GenerateMessage(int size) {
+ for (const string& message : message_cache_) {
+ if (message.size() == size) {
+ return message;
+ }
+ }
+ string message = string(size, 'x');
+ message_cache_.push_back(message);
+ return std::move(message);
+ }
+
+ optional<BlockMode> getBlockMode(string transform) {
+ if (transform.find("/ECB") != string::npos) {
+ return BlockMode::ECB;
+ } else if (transform.find("/CBC") != string::npos) {
+ return BlockMode::CBC;
+ } else if (transform.find("/CTR") != string::npos) {
+ return BlockMode::CTR;
+ } else if (transform.find("/GCM") != string::npos) {
+ return BlockMode::GCM;
+ }
+ return {};
+ }
+
+ PaddingMode getPadding(string transform, bool sign) {
+ if (transform.find("/PKCS7") != string::npos) {
+ return PaddingMode::PKCS7;
+ } else if (transform.find("/PSS") != string::npos) {
+ return PaddingMode::RSA_PSS;
+ } else if (transform.find("/OAEP") != string::npos) {
+ return PaddingMode::RSA_OAEP;
+ } else if (transform.find("/PKCS1") != string::npos) {
+ return sign ? PaddingMode::RSA_PKCS1_1_5_SIGN : PaddingMode::RSA_PKCS1_1_5_ENCRYPT;
+ } else if (sign && transform.find("RSA") != string::npos) {
+ // RSA defaults to PKCS1 for sign
+ return PaddingMode::RSA_PKCS1_1_5_SIGN;
+ }
+ return PaddingMode::NONE;
+ }
+
+ optional<Algorithm> getAlgorithm(string transform) {
+ if (transform.find("AES") != string::npos) {
+ return Algorithm::AES;
+ } else if (transform.find("Hmac") != string::npos) {
+ return Algorithm::HMAC;
+ } else if (transform.find("DESede") != string::npos) {
+ return Algorithm::TRIPLE_DES;
+ } else if (transform.find("RSA") != string::npos) {
+ return Algorithm::RSA;
+ } else if (transform.find("EC") != string::npos) {
+ return Algorithm::EC;
+ }
+ std::cerr << "Can't find algorithm for " << transform << std::endl;
+ return {};
+ }
+
+ Digest getDigest(string transform) {
+ if (transform.find("MD5") != string::npos) {
+ return Digest::MD5;
+ } else if (transform.find("SHA1") != string::npos ||
+ transform.find("SHA-1") != string::npos) {
+ return Digest::SHA1;
+ } else if (transform.find("SHA224") != string::npos) {
+ return Digest::SHA_2_224;
+ } else if (transform.find("SHA256") != string::npos) {
+ return Digest::SHA_2_256;
+ } else if (transform.find("SHA384") != string::npos) {
+ return Digest::SHA_2_384;
+ } else if (transform.find("SHA512") != string::npos) {
+ return Digest::SHA_2_512;
+ } else if (transform.find("RSA") != string::npos &&
+ transform.find("OAEP") != string::npos) {
+ return Digest::SHA1;
+ } else if (transform.find("Hmac") != string::npos) {
+ return Digest::SHA_2_256;
+ }
+ return Digest::NONE;
+ }
+
+ bool GenerateKey(string transform, int keySize, bool sign = false) {
+ if (transform == key_transform_) {
+ return true;
+ } else if (key_transform_ != "") {
+ // Deleting old key first
+ key_transform_ = "";
+ if (DeleteKey() != ErrorCode::OK) {
+ return false;
+ }
+ }
+ std::optional<Algorithm> algorithm = getAlgorithm(transform);
+ if (!algorithm) {
+ std::cerr << "Error: invalid algorithm " << transform << std::endl;
+ return false;
+ }
+ key_transform_ = transform;
+ AuthorizationSetBuilder authSet = AuthorizationSetBuilder()
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .Authorization(TAG_PURPOSE, KeyPurpose::ENCRYPT)
+ .Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT)
+ .Authorization(TAG_PURPOSE, KeyPurpose::SIGN)
+ .Authorization(TAG_PURPOSE, KeyPurpose::VERIFY)
+ .Authorization(TAG_KEY_SIZE, keySize)
+ .Authorization(TAG_ALGORITHM, algorithm.value())
+ .Digest(getDigest(transform))
+ .Padding(getPadding(transform, sign));
+ std::optional<BlockMode> blockMode = getBlockMode(transform);
+ if (blockMode) {
+ authSet.BlockMode(blockMode.value());
+ if (blockMode == BlockMode::GCM) {
+ authSet.Authorization(TAG_MIN_MAC_LENGTH, 128);
+ }
+ }
+ if (algorithm == Algorithm::HMAC) {
+ authSet.Authorization(TAG_MIN_MAC_LENGTH, 128);
+ }
+ if (algorithm == Algorithm::RSA) {
+ authSet.Authorization(TAG_RSA_PUBLIC_EXPONENT, 65537U);
+ authSet.SetDefaultValidity();
+ }
+ if (algorithm == Algorithm::EC) {
+ authSet.SetDefaultValidity();
+ }
+ error_ = GenerateKey(authSet);
+ return error_ == ErrorCode::OK;
+ }
+
+ AuthorizationSet getOperationParams(string transform, bool sign = false) {
+ AuthorizationSetBuilder builder = AuthorizationSetBuilder()
+ .Padding(getPadding(transform, sign))
+ .Digest(getDigest(transform));
+ std::optional<BlockMode> blockMode = getBlockMode(transform);
+ if (sign && (transform.find("Hmac") != string::npos)) {
+ builder.Authorization(TAG_MAC_LENGTH, 128);
+ }
+ if (blockMode) {
+ builder.BlockMode(*blockMode);
+ if (blockMode == BlockMode::GCM) {
+ builder.Authorization(TAG_MAC_LENGTH, 128);
+ }
+ }
+ return std::move(builder);
+ }
+
+ optional<string> Process(const string& message, const AuthorizationSet& /*in_params*/,
+ AuthorizationSet* out_params, const string& signature = "") {
+ static const int HIDL_BUFFER_LIMIT = 1 << 14; // 16KB
+ ErrorCode result;
+
+ // Update
+ AuthorizationSet update_params;
+ AuthorizationSet update_out_params;
+ string output;
+ string aidl_output;
+ int32_t input_consumed = 0;
+ int32_t aidl_input_consumed = 0;
+ while (message.length() - input_consumed > 0) {
+ result = Update(update_params, message.substr(input_consumed, HIDL_BUFFER_LIMIT),
+ &update_out_params, &aidl_output, &aidl_input_consumed);
+ if (result != ErrorCode::OK) {
+ error_ = result;
+ return {};
+ }
+ output.append(aidl_output);
+ input_consumed += aidl_input_consumed;
+ aidl_output.clear();
+ }
+
+ // Finish
+ AuthorizationSet finish_params;
+ AuthorizationSet finish_out_params;
+ result = Finish(finish_params, message.substr(input_consumed), signature,
+ &finish_out_params, &aidl_output);
+ if (result != ErrorCode::OK) {
+ error_ = result;
+ return {};
+ }
+ output.append(aidl_output);
+ out_params->push_back(finish_out_params);
+ return output;
+ }
+
+ ErrorCode DeleteKey() {
+ Status result = keymint_->deleteKey(key_blob_);
+ key_blob_ = vector<uint8_t>();
+ return GetReturnErrorCode(result);
+ }
+
+ ErrorCode Begin(KeyPurpose purpose, const AuthorizationSet& in_params,
+ AuthorizationSet* out_params) {
+ Status result;
+ BeginResult out;
+ result = keymint_->begin(purpose, key_blob_, in_params.vector_data(), HardwareAuthToken(),
+ &out);
+ if (result.isOk()) {
+ *out_params = out.params;
+ op_ = out.operation;
+ }
+ return GetReturnErrorCode(result);
+ }
+
+ SecurityLevel securityLevel_;
+ string name_;
+
+ private:
+ ErrorCode GenerateKey(const AuthorizationSet& key_desc,
+ const optional<AttestationKey>& attest_key = std::nullopt) {
+ key_blob_.clear();
+ KeyCreationResult creationResult;
+ Status result = keymint_->generateKey(key_desc.vector_data(), attest_key, &creationResult);
+ if (result.isOk()) {
+ key_blob_ = std::move(creationResult.keyBlob);
+ creationResult.keyCharacteristics.clear();
+ creationResult.certificateChain.clear();
+ }
+ return GetReturnErrorCode(result);
+ }
+
+ void InitializeKeyMint(std::shared_ptr<IKeyMintDevice> keyMint) {
+ if (!keyMint) {
+ std::cerr << "Trying initialize nullptr in InitializeKeyMint" << std::endl;
+ return;
+ }
+ keymint_ = std::move(keyMint);
+ KeyMintHardwareInfo info;
+ Status result = keymint_->getHardwareInfo(&info);
+ if (!result.isOk()) {
+ std::cerr << "InitializeKeyMint: getHardwareInfo failed with "
+ << result.getServiceSpecificError() << std::endl;
+ }
+ securityLevel_ = info.securityLevel;
+ name_.assign(info.keyMintName.begin(), info.keyMintName.end());
+ }
+
+ ErrorCode Finish(const AuthorizationSet& in_params, const string& input,
+ const string& signature, AuthorizationSet* out_params, string* output) {
+ Status result;
+ if (!op_) {
+ std::cerr << "Finish: Operation is nullptr" << std::endl;
+ return ErrorCode::UNEXPECTED_NULL_POINTER;
+ }
+ KeyParameterArray key_params;
+ key_params.params = in_params.vector_data();
+
+ KeyParameterArray in_keyParams;
+ in_keyParams.params = in_params.vector_data();
+
+ std::optional<KeyParameterArray> out_keyParams;
+ std::optional<vector<uint8_t>> o_put;
+
+ vector<uint8_t> oPut;
+ result = op_->finish(in_keyParams, vector<uint8_t>(input.begin(), input.end()),
+ vector<uint8_t>(signature.begin(), signature.end()), {}, {},
+ &out_keyParams, &oPut);
+
+ if (result.isOk()) {
+ if (out_keyParams) {
+ out_params->push_back(AuthorizationSet(out_keyParams->params));
+ }
+ output->append(oPut.begin(), oPut.end());
+ }
+ op_.reset();
+ return GetReturnErrorCode(result);
+ }
+
+ ErrorCode Update(const AuthorizationSet& in_params, const string& input,
+ AuthorizationSet* out_params, string* output, int32_t* input_consumed) {
+ Status result;
+ if (!op_) {
+ std::cerr << "Update: Operation is nullptr" << std::endl;
+ return ErrorCode::UNEXPECTED_NULL_POINTER;
+ }
+
+ KeyParameterArray key_params;
+ key_params.params = in_params.vector_data();
+
+ KeyParameterArray in_keyParams;
+ in_keyParams.params = in_params.vector_data();
+
+ std::optional<KeyParameterArray> out_keyParams;
+ std::optional<ByteArray> o_put;
+ result = op_->update(in_keyParams, vector<uint8_t>(input.begin(), input.end()), {}, {},
+ &out_keyParams, &o_put, input_consumed);
+
+ if (result.isOk()) {
+ if (o_put) {
+ output->append(o_put->data.begin(), o_put->data.end());
+ }
+
+ if (out_keyParams) {
+ out_params->push_back(AuthorizationSet(out_keyParams->params));
+ }
+ }
+
+ return GetReturnErrorCode(result);
+ }
+
+ ErrorCode GetReturnErrorCode(const Status& result) {
+ error_ = static_cast<ErrorCode>(result.getServiceSpecificError());
+ if (result.isOk()) return ErrorCode::OK;
+
+ if (result.getExceptionCode() == EX_SERVICE_SPECIFIC) {
+ return static_cast<ErrorCode>(result.getServiceSpecificError());
+ }
+
+ return ErrorCode::UNKNOWN_ERROR;
+ }
+
+ std::shared_ptr<IKeyMintOperation> op_;
+ vector<Certificate> cert_chain_;
+ vector<uint8_t> key_blob_;
+ vector<KeyCharacteristics> key_characteristics_;
+ std::shared_ptr<IKeyMintDevice> keymint_;
+ std::vector<string> message_cache_;
+ std::string key_transform_;
+ ErrorCode error_;
+};
+
+KeyMintBenchmarkTest* keymintTest;
+
+static void settings(benchmark::internal::Benchmark* benchmark) {
+ benchmark->Unit(benchmark::kMillisecond);
+}
+
+static void addDefaultLabel(benchmark::State& state) {
+ std::string secLevel;
+ switch (keymintTest->securityLevel_) {
+ case SecurityLevel::STRONGBOX:
+ secLevel = "STRONGBOX";
+ break;
+ case SecurityLevel::SOFTWARE:
+ secLevel = "SOFTWARE";
+ break;
+ case SecurityLevel::TRUSTED_ENVIRONMENT:
+ secLevel = "TEE";
+ break;
+ case SecurityLevel::KEYSTORE:
+ secLevel = "KEYSTORE";
+ break;
+ }
+ state.SetLabel("hardware_name:" + keymintTest->name_ + " sec_level:" + secLevel);
+}
+
+// clang-format off
+#define BENCHMARK_KM(func, transform, keySize) \
+ BENCHMARK_CAPTURE(func, transform/keySize, #transform "/" #keySize, keySize)->Apply(settings);
+#define BENCHMARK_KM_MSG(func, transform, keySize, msgSize) \
+ BENCHMARK_CAPTURE(func, transform/keySize/msgSize, #transform "/" #keySize "/" #msgSize, \
+ keySize, msgSize) \
+ ->Apply(settings);
+
+#define BENCHMARK_KM_ALL_MSGS(func, transform, keySize) \
+ BENCHMARK_KM_MSG(func, transform, keySize, SMALL_MESSAGE_SIZE) \
+ BENCHMARK_KM_MSG(func, transform, keySize, MEDIUM_MESSAGE_SIZE) \
+ BENCHMARK_KM_MSG(func, transform, keySize, LARGE_MESSAGE_SIZE)
+
+#define BENCHMARK_KM_CIPHER(transform, keySize, msgSize) \
+ BENCHMARK_KM_MSG(encrypt, transform, keySize, msgSize) \
+ BENCHMARK_KM_MSG(decrypt, transform, keySize, msgSize)
+
+#define BENCHMARK_KM_CIPHER_ALL_MSGS(transform, keySize) \
+ BENCHMARK_KM_ALL_MSGS(encrypt, transform, keySize) \
+ BENCHMARK_KM_ALL_MSGS(decrypt, transform, keySize)
+
+#define BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, keySize) \
+ BENCHMARK_KM_ALL_MSGS(sign, transform, keySize) \
+ BENCHMARK_KM_ALL_MSGS(verify, transform, keySize)
+// clang-format on
+
+/*
+ * ============= KeyGen TESTS ==================
+ */
+static void keygen(benchmark::State& state, string transform, int keySize) {
+ addDefaultLabel(state);
+ for (auto _ : state) {
+ if (!keymintTest->GenerateKey(transform, keySize)) {
+ state.SkipWithError(
+ ("Key generation error, " + std::to_string(keymintTest->getError())).c_str());
+ }
+ state.PauseTiming();
+
+ keymintTest->DeleteKey();
+ state.ResumeTiming();
+ }
+}
+
+BENCHMARK_KM(keygen, AES, 128);
+BENCHMARK_KM(keygen, AES, 256);
+
+BENCHMARK_KM(keygen, RSA, 2048);
+BENCHMARK_KM(keygen, RSA, 3072);
+BENCHMARK_KM(keygen, RSA, 4096);
+
+BENCHMARK_KM(keygen, EC, 224);
+BENCHMARK_KM(keygen, EC, 256);
+BENCHMARK_KM(keygen, EC, 384);
+BENCHMARK_KM(keygen, EC, 521);
+
+BENCHMARK_KM(keygen, DESede, 168);
+
+BENCHMARK_KM(keygen, Hmac, 64);
+BENCHMARK_KM(keygen, Hmac, 128);
+BENCHMARK_KM(keygen, Hmac, 256);
+BENCHMARK_KM(keygen, Hmac, 512);
+
+/*
+ * ============= SIGNATURE TESTS ==================
+ */
+
+static void sign(benchmark::State& state, string transform, int keySize, int msgSize) {
+ addDefaultLabel(state);
+ if (!keymintTest->GenerateKey(transform, keySize, true)) {
+ state.SkipWithError(
+ ("Key generation error, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+
+ auto in_params = keymintTest->getOperationParams(transform, true);
+ AuthorizationSet out_params;
+ string message = keymintTest->GenerateMessage(msgSize);
+
+ for (auto _ : state) {
+ state.PauseTiming();
+ ErrorCode error = keymintTest->Begin(KeyPurpose::SIGN, in_params, &out_params);
+ if (error != ErrorCode::OK) {
+ state.SkipWithError(
+ ("Error beginning sign, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+ state.ResumeTiming();
+ out_params.Clear();
+ if (!keymintTest->Process(message, in_params, &out_params)) {
+ state.SkipWithError(("Sign error, " + std::to_string(keymintTest->getError())).c_str());
+ break;
+ }
+ }
+}
+
+static void verify(benchmark::State& state, string transform, int keySize, int msgSize) {
+ addDefaultLabel(state);
+ if (!keymintTest->GenerateKey(transform, keySize, true)) {
+ state.SkipWithError(
+ ("Key generation error, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+ AuthorizationSet out_params;
+ auto in_params = keymintTest->getOperationParams(transform, true);
+ string message = keymintTest->GenerateMessage(msgSize);
+ ErrorCode error = keymintTest->Begin(KeyPurpose::SIGN, in_params, &out_params);
+ if (error != ErrorCode::OK) {
+ state.SkipWithError(
+ ("Error beginning sign, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+ std::optional<string> signature = keymintTest->Process(message, in_params, &out_params);
+ if (!signature) {
+ state.SkipWithError(("Sign error, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+ out_params.Clear();
+ if (transform.find("Hmac") != string::npos) {
+ in_params = keymintTest->getOperationParams(transform, false);
+ }
+ for (auto _ : state) {
+ state.PauseTiming();
+ error = keymintTest->Begin(KeyPurpose::VERIFY, in_params, &out_params);
+ if (error != ErrorCode::OK) {
+ state.SkipWithError(
+ ("Verify begin error, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+ state.ResumeTiming();
+ if (!keymintTest->Process(message, in_params, &out_params, *signature)) {
+ state.SkipWithError(
+ ("Verify error, " + std::to_string(keymintTest->getError())).c_str());
+ break;
+ }
+ }
+}
+
+// clang-format off
+#define BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(transform) \
+ BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 64) \
+ BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 128) \
+ BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 256) \
+ BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 512)
+
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA1)
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA256)
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA224)
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA256)
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA384)
+BENCHMARK_KM_SIGNATURE_ALL_HMAC_KEYS(HmacSHA512)
+
+#define BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(transform) \
+ BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 224) \
+ BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 256) \
+ BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 384) \
+ BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 521)
+
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(NONEwithECDSA);
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA1withECDSA);
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA224withECDSA);
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA256withECDSA);
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA384withECDSA);
+BENCHMARK_KM_SIGNATURE_ALL_ECDSA_KEYS(SHA512withECDSA);
+
+#define BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(transform) \
+ BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 2048) \
+ BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 3072) \
+ BENCHMARK_KM_SIGNATURE_ALL_MSGS(transform, 4096)
+
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(MD5withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA1withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA224withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA384withRSA);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA512withRSA);
+
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(MD5withRSA/PSS);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA1withRSA/PSS);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA224withRSA/PSS);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA384withRSA/PSS);
+BENCHMARK_KM_SIGNATURE_ALL_RSA_KEYS(SHA512withRSA/PSS);
+// clang-format on
+
+/*
+ * ============= CIPHER TESTS ==================
+ */
+
+static void encrypt(benchmark::State& state, string transform, int keySize, int msgSize) {
+ addDefaultLabel(state);
+ if (!keymintTest->GenerateKey(transform, keySize)) {
+ state.SkipWithError(
+ ("Key generation error, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+ auto in_params = keymintTest->getOperationParams(transform);
+ AuthorizationSet out_params;
+ string message = keymintTest->GenerateMessage(msgSize);
+
+ for (auto _ : state) {
+ state.PauseTiming();
+ auto error = keymintTest->Begin(KeyPurpose::ENCRYPT, in_params, &out_params);
+ if (error != ErrorCode::OK) {
+ state.SkipWithError(
+ ("Encryption begin error, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+ out_params.Clear();
+ state.ResumeTiming();
+ if (!keymintTest->Process(message, in_params, &out_params)) {
+ state.SkipWithError(
+ ("Encryption error, " + std::to_string(keymintTest->getError())).c_str());
+ break;
+ }
+ }
+}
+
+static void decrypt(benchmark::State& state, string transform, int keySize, int msgSize) {
+ addDefaultLabel(state);
+ if (!keymintTest->GenerateKey(transform, keySize)) {
+ state.SkipWithError(
+ ("Key generation error, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+ AuthorizationSet out_params;
+ AuthorizationSet in_params = keymintTest->getOperationParams(transform);
+ string message = keymintTest->GenerateMessage(msgSize);
+ auto error = keymintTest->Begin(KeyPurpose::ENCRYPT, in_params, &out_params);
+ if (error != ErrorCode::OK) {
+ state.SkipWithError(
+ ("Encryption begin error, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+ auto encryptedMessage = keymintTest->Process(message, in_params, &out_params);
+ if (!encryptedMessage) {
+ state.SkipWithError(
+ ("Encryption error, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+ in_params.push_back(out_params);
+ out_params.Clear();
+ for (auto _ : state) {
+ state.PauseTiming();
+ error = keymintTest->Begin(KeyPurpose::DECRYPT, in_params, &out_params);
+ if (error != ErrorCode::OK) {
+ state.SkipWithError(
+ ("Decryption begin error, " + std::to_string(keymintTest->getError())).c_str());
+ return;
+ }
+ state.ResumeTiming();
+ if (!keymintTest->Process(*encryptedMessage, in_params, &out_params)) {
+ state.SkipWithError(
+ ("Decryption error, " + std::to_string(keymintTest->getError())).c_str());
+ break;
+ }
+ }
+}
+
+// clang-format off
+// AES
+#define BENCHMARK_KM_CIPHER_ALL_AES_KEYS(transform) \
+ BENCHMARK_KM_CIPHER_ALL_MSGS(transform, 128) \
+ BENCHMARK_KM_CIPHER_ALL_MSGS(transform, 256)
+
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/CBC/NoPadding);
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/CBC/PKCS7Padding);
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/CTR/NoPadding);
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/ECB/NoPadding);
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/ECB/PKCS7Padding);
+BENCHMARK_KM_CIPHER_ALL_AES_KEYS(AES/GCM/NoPadding);
+
+// Triple DES
+BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/CBC/NoPadding, 168);
+BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/CBC/PKCS7Padding, 168);
+BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/ECB/NoPadding, 168);
+BENCHMARK_KM_CIPHER_ALL_MSGS(DESede/ECB/PKCS7Padding, 168);
+
+#define BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(transform, msgSize) \
+ BENCHMARK_KM_CIPHER(transform, 2048, msgSize) \
+ BENCHMARK_KM_CIPHER(transform, 3072, msgSize) \
+ BENCHMARK_KM_CIPHER(transform, 4096, msgSize)
+
+BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/NoPadding, SMALL_MESSAGE_SIZE);
+BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/PKCS1Padding, SMALL_MESSAGE_SIZE);
+BENCHMARK_KM_CIPHER_ALL_RSA_KEYS(RSA/ECB/OAEPPadding, SMALL_MESSAGE_SIZE);
+
+// clang-format on
+} // namespace aidl::android::hardware::security::keymint::test
+
+int main(int argc, char** argv) {
+ ::benchmark::Initialize(&argc, argv);
+ base::CommandLine::Init(argc, argv);
+ base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
+ auto service_name = command_line->GetSwitchValueASCII("service_name");
+ if (service_name.empty()) {
+ service_name =
+ std::string(
+ aidl::android::hardware::security::keymint::IKeyMintDevice::descriptor) +
+ "/default";
+ }
+ std::cerr << service_name << std::endl;
+ aidl::android::hardware::security::keymint::test::keymintTest =
+ aidl::android::hardware::security::keymint::test::KeyMintBenchmarkTest::newInstance(
+ service_name.c_str());
+ if (!aidl::android::hardware::security::keymint::test::keymintTest) {
+ return 1;
+ }
+ ::benchmark::RunSpecifiedBenchmarks();
+}
diff --git a/security/keymint/aidl/vts/performance/README b/security/keymint/aidl/vts/performance/README
new file mode 100644
index 0000000..1221ad8
--- /dev/null
+++ b/security/keymint/aidl/vts/performance/README
@@ -0,0 +1,28 @@
+# KeyMint Benchmark
+
+The KeyMint Benchmark is a standalone tool for measuring the performance of
+ KeyMint implementations.
+
+## Building
+
+Build:
+`m VtsAidlKeyMintBenchmarkTest`
+
+Transfer to device/emulator:
+`adb sync data`
+
+The benchmark executable will be located at
+ `data/benchmarktest/VtsAidlKeyMintBenchmarkTest` on the device.
+
+## Usage
+
+KeyMint Benchmark is built on [Google microbenchmark
+library](https://github.com/google/benchmark). All of the commandline arguments
+provided by the microbenchmark library are valid, such as
+`--benchmark_filter=<regex>` or `benchmark_out_format={json|console|csv}`.
+In addition to the command line arguments provided by microbenchmark,
+`--service_name=<service_name>` is provided to allow specification of the KeyMint
+fully qualified service name, e.g. specify
+`--service_name=android.hardware.security.keymint.IKeyMintDevice/default` to
+benchmark default implementation of KeyMint.
+
diff --git a/security/keymint/support/Android.bp b/security/keymint/support/Android.bp
index efdff2b..0255874 100644
--- a/security/keymint/support/Android.bp
+++ b/security/keymint/support/Android.bp
@@ -71,6 +71,6 @@
],
static_libs: [
// TODO(swillden): Remove keymint NDK
- "android.hardware.security.keymint-unstable-ndk_platform",
+ "android.hardware.security.keymint-V1-ndk_platform",
],
}
diff --git a/security/keymint/support/authorization_set.cpp b/security/keymint/support/authorization_set.cpp
index 8d42571..25eace3 100644
--- a/security/keymint/support/authorization_set.cpp
+++ b/security/keymint/support/authorization_set.cpp
@@ -191,6 +191,10 @@
return Authorization(TAG_PURPOSE, KeyPurpose::DECRYPT);
}
+AuthorizationSetBuilder& AuthorizationSetBuilder::AttestKey() {
+ return Authorization(TAG_PURPOSE, KeyPurpose::ATTEST_KEY);
+}
+
AuthorizationSetBuilder& AuthorizationSetBuilder::NoDigestOrPadding() {
Authorization(TAG_DIGEST, Digest::NONE);
return Authorization(TAG_PADDING, PaddingMode::NONE);
diff --git a/security/keymint/support/include/keymint_support/authorization_set.h b/security/keymint/support/include/keymint_support/authorization_set.h
index 6d36794..ca51b08 100644
--- a/security/keymint/support/include/keymint_support/authorization_set.h
+++ b/security/keymint/support/include/keymint_support/authorization_set.h
@@ -288,6 +288,7 @@
AuthorizationSetBuilder& SigningKey();
AuthorizationSetBuilder& EncryptionKey();
+ AuthorizationSetBuilder& AttestKey();
AuthorizationSetBuilder& NoDigestOrPadding();
diff --git a/security/keymint/support/include/keymint_support/openssl_utils.h b/security/keymint/support/include/keymint_support/openssl_utils.h
index c3bc60b..a0212aa 100644
--- a/security/keymint/support/include/keymint_support/openssl_utils.h
+++ b/security/keymint/support/include/keymint_support/openssl_utils.h
@@ -34,13 +34,14 @@
typedef std::unique_ptr<type, UniquePtrDeleter<type, type##_free>> type##_Ptr;
MAKE_OPENSSL_PTR_TYPE(ASN1_OBJECT)
-MAKE_OPENSSL_PTR_TYPE(EC_KEY)
+MAKE_OPENSSL_PTR_TYPE(BN_CTX)
MAKE_OPENSSL_PTR_TYPE(EC_GROUP)
+MAKE_OPENSSL_PTR_TYPE(EC_KEY)
MAKE_OPENSSL_PTR_TYPE(EVP_PKEY)
MAKE_OPENSSL_PTR_TYPE(EVP_PKEY_CTX)
MAKE_OPENSSL_PTR_TYPE(RSA)
MAKE_OPENSSL_PTR_TYPE(X509)
-MAKE_OPENSSL_PTR_TYPE(BN_CTX)
+MAKE_OPENSSL_PTR_TYPE(X509_NAME)
typedef std::unique_ptr<BIGNUM, UniquePtrDeleter<BIGNUM, BN_free>> BIGNUM_Ptr;
diff --git a/security/secureclock/aidl/vts/functional/Android.bp b/security/secureclock/aidl/vts/functional/Android.bp
index 30244eb..1619eab 100644
--- a/security/secureclock/aidl/vts/functional/Android.bp
+++ b/security/secureclock/aidl/vts/functional/Android.bp
@@ -33,8 +33,8 @@
"libkeymint",
],
static_libs: [
- "android.hardware.security.keymint-unstable-ndk_platform",
- "android.hardware.security.secureclock-unstable-ndk_platform",
+ "android.hardware.security.keymint-V1-ndk_platform",
+ "android.hardware.security.secureclock-V1-ndk_platform",
],
test_suites: [
"general-tests",
diff --git a/security/sharedsecret/aidl/vts/functional/Android.bp b/security/sharedsecret/aidl/vts/functional/Android.bp
index 56ab317..76bf7ff 100644
--- a/security/sharedsecret/aidl/vts/functional/Android.bp
+++ b/security/sharedsecret/aidl/vts/functional/Android.bp
@@ -33,8 +33,8 @@
"libkeymint",
],
static_libs: [
- "android.hardware.security.keymint-unstable-ndk_platform",
- "android.hardware.security.sharedsecret-unstable-ndk_platform",
+ "android.hardware.security.keymint-V1-ndk_platform",
+ "android.hardware.security.sharedsecret-V1-ndk_platform",
],
test_suites: [
"general-tests",