Merge changes from topic "dynamicConfig"
* changes:
Add descrambler dynamic configuration into Tuner 1.0 VTS
Add lnb/timeFilter dynamic configuration into Tuner 1.0 VTS
Add filter dynamic configuration into Tuner 1.0 VTS
Add dvr dynamic configuration into Tuner 1.0 VTS
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/Ashmem.aidl b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/Ashmem.aidl
new file mode 100644
index 0000000..a438031
--- /dev/null
+++ b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/Ashmem.aidl
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.common;
+@VintfStability
+parcelable Ashmem {
+ ParcelFileDescriptor fd;
+ long size;
+}
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MappableFile.aidl b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MappableFile.aidl
new file mode 100644
index 0000000..394ea8f
--- /dev/null
+++ b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/MappableFile.aidl
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+///////////////////////////////////////////////////////////////////////////////
+// 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.common;
+@VintfStability
+parcelable MappableFile {
+ long length;
+ int prot;
+ ParcelFileDescriptor fd;
+ long offset;
+}
diff --git a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl
index f37b7d5..2ed5c0b 100644
--- a/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl
+++ b/common/aidl/aidl_api/android.hardware.common/current/android/hardware/common/NativeHandle.aidl
@@ -1,14 +1,30 @@
+/*
+ * Copyright 2019 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 interface (or parcelable). Do not try to
-// edit this file. It looks like you are doing that because you have modified
-// an AIDL interface in a backward-incompatible way, e.g., deleting a function
-// from an interface or a field from a parcelable and it broke the build. That
-// breakage is intended.
+// 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 changes to the AIDL files built
+// 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
diff --git a/common/aidl/android/hardware/common/Ashmem.aidl b/common/aidl/android/hardware/common/Ashmem.aidl
new file mode 100644
index 0000000..8e40266
--- /dev/null
+++ b/common/aidl/android/hardware/common/Ashmem.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.common;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * Type that holds same memory as the "ashmem" hidl_memory type from HIDL.
+ */
+@VintfStability
+parcelable Ashmem {
+ /**
+ * A handle to a memory region.
+ */
+ ParcelFileDescriptor fd;
+ /**
+ * Size of the memory region in bytes.
+ */
+ long size;
+}
diff --git a/common/aidl/android/hardware/common/MappableFile.aidl b/common/aidl/android/hardware/common/MappableFile.aidl
new file mode 100644
index 0000000..a7763ea
--- /dev/null
+++ b/common/aidl/android/hardware/common/MappableFile.aidl
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.hardware.common;
+
+import android.os.ParcelFileDescriptor;
+
+/**
+ * A region of a file that can be mapped into memory.
+ *
+ * In Linux, MappableFile may be used with mmap as `MAP_SHARED`.
+ *
+ * MappableFile is compatible with ::android::base::MappedFile.
+ */
+@VintfStability
+parcelable MappableFile {
+ /**
+ * Length of the mapping region in bytes.
+ */
+ long length;
+ /**
+ * The desired memory protection for the mapping.
+ *
+ * In Linux, prot is either `PROT_NONE` (indicating that mapped pages may not be accessed) or
+ * the bitwise OR of one or more of the following flags:
+ * - `PROT_READ` (indicating that the mapped pages may be read)
+ * - `PROT_WRITE` (indicating that the mapped pages may be written)
+ */
+ int prot;
+ /**
+ * A handle to a mappable file.
+ */
+ ParcelFileDescriptor fd;
+ /**
+ * The offset in the file to the beginning of the mapping region in number of bytes.
+ *
+ * Note: Some mapping functions require that the offset is aligned to the page size.
+ */
+ long offset;
+}
diff --git a/common/support/Android.bp b/common/support/Android.bp
index 8aea306..730798d 100644
--- a/common/support/Android.bp
+++ b/common/support/Android.bp
@@ -18,6 +18,11 @@
"android.hardware.common-V2-ndk_platform",
"libcutils",
],
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.neuralnetworks",
+ ],
+ min_sdk_version: "29",
}
cc_test {
diff --git a/drm/1.0/default/CryptoPlugin.cpp b/drm/1.0/default/CryptoPlugin.cpp
index 2db3607..e6d4e84 100644
--- a/drm/1.0/default/CryptoPlugin.cpp
+++ b/drm/1.0/default/CryptoPlugin.cpp
@@ -124,7 +124,11 @@
return Void();
}
- if (source.offset + offset + source.size > sourceBase->getSize()) {
+ size_t totalSize = 0;
+ if (__builtin_add_overflow(source.offset, offset, &totalSize) ||
+ __builtin_add_overflow(totalSize, source.size, &totalSize) ||
+ totalSize > sourceBase->getSize()) {
+ android_errorWriteLog(0x534e4554, "176496160");
_hidl_cb(Status::ERROR_DRM_CANNOT_HANDLE, 0, "invalid buffer size");
return Void();
}
diff --git a/graphics/common/aidl/Android.bp b/graphics/common/aidl/Android.bp
index 2a46f9d..cadd13c 100644
--- a/graphics/common/aidl/Android.bp
+++ b/graphics/common/aidl/Android.bp
@@ -34,6 +34,7 @@
apex_available: [
"//apex_available:platform",
"com.android.media.swcodec",
+ "com.android.neuralnetworks",
],
min_sdk_version: "29",
},
diff --git a/identity/aidl/default/Android.bp b/identity/aidl/default/Android.bp
index 05b3662..a124b1e 100644
--- a/identity/aidl/default/Android.bp
+++ b/identity/aidl/default/Android.bp
@@ -31,7 +31,7 @@
],
static_libs: [
"libbase",
- "libcppbor",
+ "libcppbor_external",
"libutils",
"libsoft_attestation_cert",
"libkeymaster_portable",
@@ -91,7 +91,7 @@
],
static_libs: [
"libbase",
- "libcppbor",
+ "libcppbor_external",
"libutils",
"libsoft_attestation_cert",
"libkeymaster_portable",
diff --git a/identity/aidl/default/common/IdentityCredential.cpp b/identity/aidl/default/common/IdentityCredential.cpp
index c8ee0dd..95557b5 100644
--- a/identity/aidl/default/common/IdentityCredential.cpp
+++ b/identity/aidl/default/common/IdentityCredential.cpp
@@ -488,7 +488,7 @@
}
for (size_t n = 0; n < nsMap->size(); n++) {
- auto [nsKeyItem, nsValueItem] = (*nsMap)[n];
+ auto& [nsKeyItem, nsValueItem] = (*nsMap)[n];
const cppbor::Tstr* nsKey = nsKeyItem->asTstr();
const cppbor::Map* nsInnerMap = nsValueItem->asMap();
if (nsKey == nullptr || nsInnerMap == nullptr) {
diff --git a/identity/aidl/default/common/IdentityCredential.h b/identity/aidl/default/common/IdentityCredential.h
index 9913b86..ef9d133 100644
--- a/identity/aidl/default/common/IdentityCredential.h
+++ b/identity/aidl/default/common/IdentityCredential.h
@@ -27,7 +27,7 @@
#include <string>
#include <vector>
-#include <cppbor/cppbor.h>
+#include <cppbor.h>
#include "IdentityCredentialStore.h"
#include "SecureHardwareProxy.h"
diff --git a/identity/aidl/default/common/WritableIdentityCredential.cpp b/identity/aidl/default/common/WritableIdentityCredential.cpp
index 2d897c7..25f129b 100644
--- a/identity/aidl/default/common/WritableIdentityCredential.cpp
+++ b/identity/aidl/default/common/WritableIdentityCredential.cpp
@@ -23,8 +23,8 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
-#include <cppbor/cppbor.h>
-#include <cppbor/cppbor_parse.h>
+#include <cppbor.h>
+#include <cppbor_parse.h>
#include <utility>
diff --git a/identity/aidl/vts/Android.bp b/identity/aidl/vts/Android.bp
index 82c4011..3592d3e 100644
--- a/identity/aidl/vts/Android.bp
+++ b/identity/aidl/vts/Android.bp
@@ -34,7 +34,7 @@
"libcrypto",
],
static_libs: [
- "libcppbor",
+ "libcppbor_external",
"libkeymaster_portable",
"libpuresoftkeymasterdevice",
"android.hardware.keymaster@4.0",
diff --git a/identity/aidl/vts/AuthenticationKeyTests.cpp b/identity/aidl/vts/AuthenticationKeyTests.cpp
index bda3e70..25d74d4 100644
--- a/identity/aidl/vts/AuthenticationKeyTests.cpp
+++ b/identity/aidl/vts/AuthenticationKeyTests.cpp
@@ -118,7 +118,7 @@
optional<vector<uint8_t>> proofOfProvisioning =
support::coseSignGetPayload(proofOfProvisioningSignature);
ASSERT_TRUE(proofOfProvisioning);
- string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {});
+ string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {});
EXPECT_EQ(
"[\n"
" 'ProofOfProvisioning',\n"
diff --git a/identity/aidl/vts/DeleteCredentialTests.cpp b/identity/aidl/vts/DeleteCredentialTests.cpp
index 1d30067..d3addf4 100644
--- a/identity/aidl/vts/DeleteCredentialTests.cpp
+++ b/identity/aidl/vts/DeleteCredentialTests.cpp
@@ -126,7 +126,7 @@
optional<vector<uint8_t>> proofOfDeletion =
support::coseSignGetPayload(proofOfDeletionSignature);
ASSERT_TRUE(proofOfDeletion);
- string cborPretty = support::cborPrettyPrint(proofOfDeletion.value(), 32, {});
+ string cborPretty = cppbor::prettyPrint(proofOfDeletion.value(), 32, {});
EXPECT_EQ("['ProofOfDeletion', 'org.iso.18013-5.2019.mdl', true, ]", cborPretty);
EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfDeletionSignature, {}, // Additional data
credentialPubKey_));
@@ -153,7 +153,7 @@
optional<vector<uint8_t>> proofOfDeletion =
support::coseSignGetPayload(proofOfDeletionSignature);
ASSERT_TRUE(proofOfDeletion);
- string cborPretty = support::cborPrettyPrint(proofOfDeletion.value(), 32, {});
+ string cborPretty = cppbor::prettyPrint(proofOfDeletion.value(), 32, {});
EXPECT_EQ("['ProofOfDeletion', 'org.iso.18013-5.2019.mdl', {0x41, 0x42, 0x43}, true, ]",
cborPretty);
EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfDeletionSignature, {}, // Additional data
diff --git a/identity/aidl/vts/EndToEndTests.cpp b/identity/aidl/vts/EndToEndTests.cpp
index 5798b4c..67db915 100644
--- a/identity/aidl/vts/EndToEndTests.cpp
+++ b/identity/aidl/vts/EndToEndTests.cpp
@@ -231,7 +231,7 @@
optional<vector<uint8_t>> proofOfProvisioning =
support::coseSignGetPayload(proofOfProvisioningSignature);
ASSERT_TRUE(proofOfProvisioning);
- cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
+ cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
EXPECT_EQ(
"[\n"
" 'ProofOfProvisioning',\n"
@@ -339,8 +339,8 @@
vector<uint8_t> deviceEngagementBytes = deviceEngagement.encode();
vector<uint8_t> eReaderPubBytes = cppbor::Tstr("ignored").encode();
cppbor::Array sessionTranscript = cppbor::Array()
- .add(cppbor::Semantic(24, deviceEngagementBytes))
- .add(cppbor::Semantic(24, eReaderPubBytes));
+ .add(cppbor::SemanticTag(24, deviceEngagementBytes))
+ .add(cppbor::SemanticTag(24, eReaderPubBytes));
vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
vector<uint8_t> itemsRequestBytes =
@@ -353,7 +353,7 @@
.add("Home address", true))
.add("Image", cppbor::Map().add("Portrait image", false)))
.encode();
- cborPretty = support::cborPrettyPrint(itemsRequestBytes, 32, {"EphemeralPublicKey"});
+ cborPretty = cppbor::prettyPrint(itemsRequestBytes, 32, {"EphemeralPublicKey"});
EXPECT_EQ(
"{\n"
" 'nameSpaces' : {\n"
@@ -373,10 +373,10 @@
cppbor::Array()
.add("ReaderAuthentication")
.add(sessionTranscript.clone())
- .add(cppbor::Semantic(24, itemsRequestBytes))
+ .add(cppbor::SemanticTag(24, itemsRequestBytes))
.encode();
vector<uint8_t> encodedReaderAuthenticationBytes =
- cppbor::Semantic(24, encodedReaderAuthentication).encode();
+ cppbor::SemanticTag(24, encodedReaderAuthentication).encode();
optional<vector<uint8_t>> readerSignature =
support::coseSignEcDsa(readerKey, {}, // content
encodedReaderAuthenticationBytes, // detached content
@@ -443,7 +443,7 @@
vector<uint8_t> mac;
vector<uint8_t> deviceNameSpacesEncoded;
ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
- cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
+ cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
ASSERT_EQ(
"{\n"
" 'PersonalData' : {\n"
@@ -462,10 +462,11 @@
string docType = "org.iso.18013-5.2019.mdl";
optional<vector<uint8_t>> readerEphemeralPrivateKey =
support::ecKeyPairGetPrivateKey(readerEphemeralKeyPair.value());
- optional<vector<uint8_t>> eMacKey = support::calcEMacKey(
- readerEphemeralPrivateKey.value(), // Private Key
- signingPubKey.value(), // Public Key
- cppbor::Semantic(24, sessionTranscript.encode()).encode()); // SessionTranscriptBytes
+ optional<vector<uint8_t>> eMacKey =
+ support::calcEMacKey(readerEphemeralPrivateKey.value(), // Private Key
+ signingPubKey.value(), // Public Key
+ cppbor::SemanticTag(24, sessionTranscript.encode())
+ .encode()); // SessionTranscriptBytes
optional<vector<uint8_t>> calculatedMac =
support::calcMac(sessionTranscript.encode(), // SessionTranscript
docType, // DocType
@@ -486,7 +487,7 @@
testEntriesEntryCounts)
.isOk());
ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
- cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
+ cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
ASSERT_EQ("{}", cborPretty);
// Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
calculatedMac = support::calcMac(sessionTranscript.encode(), // SessionTranscript
@@ -508,7 +509,7 @@
testEntriesEntryCounts)
.isOk());
ASSERT_TRUE(credential->finishRetrieval(&mac, &deviceNameSpacesEncoded).isOk());
- cborPretty = support::cborPrettyPrint(deviceNameSpacesEncoded, 32, {});
+ cborPretty = cppbor::prettyPrint(deviceNameSpacesEncoded, 32, {});
ASSERT_EQ("{}", cborPretty);
// Calculate DeviceAuthentication and MAC (MACing key hasn't changed)
calculatedMac = support::calcMac(sessionTranscript.encode(), // SessionTranscript
diff --git a/identity/aidl/vts/ProveOwnershipTests.cpp b/identity/aidl/vts/ProveOwnershipTests.cpp
index d1a3d39..fa0e293 100644
--- a/identity/aidl/vts/ProveOwnershipTests.cpp
+++ b/identity/aidl/vts/ProveOwnershipTests.cpp
@@ -131,7 +131,7 @@
optional<vector<uint8_t>> proofOfOwnership =
support::coseSignGetPayload(proofOfOwnershipSignature);
ASSERT_TRUE(proofOfOwnership);
- string cborPretty = support::cborPrettyPrint(proofOfOwnership.value(), 32, {});
+ string cborPretty = cppbor::prettyPrint(proofOfOwnership.value(), 32, {});
EXPECT_EQ("['ProofOfOwnership', 'org.iso.18013-5.2019.mdl', {0x11, 0x12}, true, ]", cborPretty);
EXPECT_TRUE(support::coseCheckEcDsaSignature(proofOfOwnershipSignature, {}, // Additional data
credentialPubKey_));
diff --git a/identity/aidl/vts/ReaderAuthTests.cpp b/identity/aidl/vts/ReaderAuthTests.cpp
index 7656c8e..c4a58c3 100644
--- a/identity/aidl/vts/ReaderAuthTests.cpp
+++ b/identity/aidl/vts/ReaderAuthTests.cpp
@@ -262,8 +262,8 @@
vector<uint8_t> deviceEngagementBytes = deviceEngagement.encode();
vector<uint8_t> eReaderPubBytes = cppbor::Tstr("ignored").encode();
cppbor::Array sessionTranscript = cppbor::Array()
- .add(cppbor::Semantic(24, deviceEngagementBytes))
- .add(cppbor::Semantic(24, eReaderPubBytes));
+ .add(cppbor::SemanticTag(24, deviceEngagementBytes))
+ .add(cppbor::SemanticTag(24, eReaderPubBytes));
vector<uint8_t> sessionTranscriptBytes = sessionTranscript.encode();
vector<uint8_t> itemsRequestBytes;
@@ -293,10 +293,10 @@
cppbor::Array()
.add("ReaderAuthentication")
.add(sessionTranscript.clone())
- .add(cppbor::Semantic(24, itemsRequestBytes))
+ .add(cppbor::SemanticTag(24, itemsRequestBytes))
.encode();
vector<uint8_t> encodedReaderAuthenticationBytes =
- cppbor::Semantic(24, encodedReaderAuthentication).encode();
+ cppbor::SemanticTag(24, encodedReaderAuthentication).encode();
optional<vector<uint8_t>> readerSignature =
support::coseSignEcDsa(readerPrivateKey, // private key for reader
@@ -517,8 +517,8 @@
vector<uint8_t> deviceEngagementBytes = deviceEngagement.encode();
vector<uint8_t> eReaderPubBytes = cppbor::Tstr("ignored").encode();
cppbor::Array sessionTranscript = cppbor::Array()
- .add(cppbor::Semantic(24, deviceEngagementBytes))
- .add(cppbor::Semantic(24, eReaderPubBytes));
+ .add(cppbor::SemanticTag(24, deviceEngagementBytes))
+ .add(cppbor::SemanticTag(24, eReaderPubBytes));
vector<uint8_t> sessionTranscriptBytes = sessionTranscript.encode();
vector<uint8_t> itemsRequestBytes;
@@ -535,10 +535,10 @@
cppbor::Array()
.add("ReaderAuthentication")
.add(sessionTranscript.clone())
- .add(cppbor::Semantic(24, itemsRequestBytes))
+ .add(cppbor::SemanticTag(24, itemsRequestBytes))
.encode();
vector<uint8_t> encodedReaderAuthenticationBytes =
- cppbor::Semantic(24, encodedReaderAuthentication).encode();
+ cppbor::SemanticTag(24, encodedReaderAuthentication).encode();
vector<vector<uint8_t>> readerCertChain = {cert_reader_SelfSigned_};
optional<vector<uint8_t>> readerSignature =
diff --git a/identity/aidl/vts/TestCredentialTests.cpp b/identity/aidl/vts/TestCredentialTests.cpp
index d53de3b..46c2229 100644
--- a/identity/aidl/vts/TestCredentialTests.cpp
+++ b/identity/aidl/vts/TestCredentialTests.cpp
@@ -114,7 +114,7 @@
optional<vector<uint8_t>> proofOfProvisioning =
support::coseSignGetPayload(proofOfProvisioningSignature);
ASSERT_TRUE(proofOfProvisioning);
- string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {});
+ string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {});
EXPECT_EQ(
"[\n"
" 'ProofOfProvisioning',\n"
diff --git a/identity/aidl/vts/UpdateCredentialTests.cpp b/identity/aidl/vts/UpdateCredentialTests.cpp
index 9c5ca55..e05bb3b 100644
--- a/identity/aidl/vts/UpdateCredentialTests.cpp
+++ b/identity/aidl/vts/UpdateCredentialTests.cpp
@@ -114,7 +114,7 @@
optional<vector<uint8_t>> proofOfProvisioning =
support::coseSignGetPayload(proofOfProvisioningSignature);
ASSERT_TRUE(proofOfProvisioning);
- string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {});
+ string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {});
EXPECT_EQ(
"[\n"
" 'ProofOfProvisioning',\n"
@@ -195,7 +195,7 @@
optional<vector<uint8_t>> proofOfProvisioning =
support::coseSignGetPayload(proofOfProvisioningSignature);
ASSERT_TRUE(proofOfProvisioning);
- string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(), 32, {});
+ string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {});
EXPECT_EQ(
"[\n"
" 'ProofOfProvisioning',\n"
diff --git a/identity/aidl/vts/UserAuthTests.cpp b/identity/aidl/vts/UserAuthTests.cpp
index ef89d1c..edd1725 100644
--- a/identity/aidl/vts/UserAuthTests.cpp
+++ b/identity/aidl/vts/UserAuthTests.cpp
@@ -160,8 +160,8 @@
// Let SessionTranscript be a map here (it's an array in EndToEndTest) just
// to check that the implementation can deal with either.
cppbor::Map sessionTranscript;
- sessionTranscript.add(42, cppbor::Semantic(24, deviceEngagementBytes));
- sessionTranscript.add(43, cppbor::Semantic(24, eReaderPubBytes));
+ sessionTranscript.add(42, cppbor::SemanticTag(24, deviceEngagementBytes));
+ sessionTranscript.add(43, cppbor::SemanticTag(24, eReaderPubBytes));
return sessionTranscript;
}
@@ -209,7 +209,7 @@
vector<uint8_t> dataToSign = cppbor::Array()
.add("ReaderAuthentication")
.add(sessionTranscript_.clone())
- .add(cppbor::Semantic(24, itemsRequestBytes))
+ .add(cppbor::SemanticTag(24, itemsRequestBytes))
.encode();
}
diff --git a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
index cc63c48..bc37020 100644
--- a/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
+++ b/identity/aidl/vts/VtsIWritableIdentityCredentialTests.cpp
@@ -338,8 +338,7 @@
optional<vector<uint8_t>> proofOfProvisioning =
support::coseSignGetPayload(proofOfProvisioningSignature);
ASSERT_TRUE(proofOfProvisioning);
- string cborPretty =
- support::cborPrettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
+ string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(), 32, {"readerCertificate"});
EXPECT_EQ(
"[\n"
" 'ProofOfProvisioning',\n"
@@ -449,9 +448,9 @@
optional<vector<uint8_t>> proofOfProvisioning =
support::coseSignGetPayload(proofOfProvisioningSignature);
ASSERT_TRUE(proofOfProvisioning);
- string cborPretty = support::cborPrettyPrint(proofOfProvisioning.value(),
- 32, //
- {"readerCertificate"});
+ string cborPretty = cppbor::prettyPrint(proofOfProvisioning.value(),
+ 32, //
+ {"readerCertificate"});
EXPECT_EQ(
"[\n"
" 'ProofOfProvisioning',\n"
diff --git a/identity/support/Android.bp b/identity/support/Android.bp
index d00f59a..774bc40 100644
--- a/identity/support/Android.bp
+++ b/identity/support/Android.bp
@@ -42,7 +42,7 @@
"libpuresoftkeymasterdevice",
],
static_libs: [
- "libcppbor",
+ "libcppbor_external",
],
}
@@ -59,7 +59,7 @@
"libhardware",
],
static_libs: [
- "libcppbor",
+ "libcppbor_external",
"libgmock",
],
test_suites: ["general-tests"],
@@ -89,7 +89,7 @@
"tests/cppbor_test.cpp",
],
shared_libs: [
- "libcppbor",
+ "libcppbor_external",
"libbase",
],
static_libs: [
@@ -104,7 +104,7 @@
"tests/cppbor_test.cpp",
],
shared_libs: [
- "libcppbor",
+ "libcppbor_external",
"libbase",
],
static_libs: [
diff --git a/identity/support/src/IdentityCredentialSupport.cpp b/identity/support/src/IdentityCredentialSupport.cpp
index aba89c1..4547624 100644
--- a/identity/support/src/IdentityCredentialSupport.cpp
+++ b/identity/support/src/IdentityCredentialSupport.cpp
@@ -148,199 +148,6 @@
}
// ---------------------------------------------------------------------------
-// CBOR utilities.
-// ---------------------------------------------------------------------------
-
-static bool cborAreAllElementsNonCompound(const cppbor::CompoundItem* compoundItem) {
- if (compoundItem->type() == cppbor::ARRAY) {
- const cppbor::Array* array = compoundItem->asArray();
- for (size_t n = 0; n < array->size(); n++) {
- const cppbor::Item* entry = (*array)[n].get();
- switch (entry->type()) {
- case cppbor::ARRAY:
- case cppbor::MAP:
- return false;
- default:
- break;
- }
- }
- } else {
- const cppbor::Map* map = compoundItem->asMap();
- for (size_t n = 0; n < map->size(); n++) {
- auto [keyEntry, valueEntry] = (*map)[n];
- switch (keyEntry->type()) {
- case cppbor::ARRAY:
- case cppbor::MAP:
- return false;
- default:
- break;
- }
- switch (valueEntry->type()) {
- case cppbor::ARRAY:
- case cppbor::MAP:
- return false;
- default:
- break;
- }
- }
- }
- return true;
-}
-
-static bool cborPrettyPrintInternal(const cppbor::Item* item, string& out, size_t indent,
- size_t maxBStrSize, const vector<string>& mapKeysToNotPrint) {
- char buf[80];
-
- string indentString(indent, ' ');
-
- switch (item->type()) {
- case cppbor::UINT:
- snprintf(buf, sizeof(buf), "%" PRIu64, item->asUint()->unsignedValue());
- out.append(buf);
- break;
-
- case cppbor::NINT:
- snprintf(buf, sizeof(buf), "%" PRId64, item->asNint()->value());
- out.append(buf);
- break;
-
- case cppbor::BSTR: {
- const cppbor::Bstr* bstr = item->asBstr();
- const vector<uint8_t>& value = bstr->value();
- if (value.size() > maxBStrSize) {
- unsigned char digest[SHA_DIGEST_LENGTH];
- SHA_CTX ctx;
- SHA1_Init(&ctx);
- SHA1_Update(&ctx, value.data(), value.size());
- SHA1_Final(digest, &ctx);
- char buf2[SHA_DIGEST_LENGTH * 2 + 1];
- for (size_t n = 0; n < SHA_DIGEST_LENGTH; n++) {
- snprintf(buf2 + n * 2, 3, "%02x", digest[n]);
- }
- snprintf(buf, sizeof(buf), "<bstr size=%zd sha1=%s>", value.size(), buf2);
- out.append(buf);
- } else {
- out.append("{");
- for (size_t n = 0; n < value.size(); n++) {
- if (n > 0) {
- out.append(", ");
- }
- snprintf(buf, sizeof(buf), "0x%02x", value[n]);
- out.append(buf);
- }
- out.append("}");
- }
- } break;
-
- case cppbor::TSTR:
- out.append("'");
- {
- // TODO: escape "'" characters
- out.append(item->asTstr()->value().c_str());
- }
- out.append("'");
- break;
-
- case cppbor::ARRAY: {
- const cppbor::Array* array = item->asArray();
- if (array->size() == 0) {
- out.append("[]");
- } else if (cborAreAllElementsNonCompound(array)) {
- out.append("[");
- for (size_t n = 0; n < array->size(); n++) {
- if (!cborPrettyPrintInternal((*array)[n].get(), out, indent + 2, maxBStrSize,
- mapKeysToNotPrint)) {
- return false;
- }
- out.append(", ");
- }
- out.append("]");
- } else {
- out.append("[\n" + indentString);
- for (size_t n = 0; n < array->size(); n++) {
- out.append(" ");
- if (!cborPrettyPrintInternal((*array)[n].get(), out, indent + 2, maxBStrSize,
- mapKeysToNotPrint)) {
- return false;
- }
- out.append(",\n" + indentString);
- }
- out.append("]");
- }
- } break;
-
- case cppbor::MAP: {
- const cppbor::Map* map = item->asMap();
-
- if (map->size() == 0) {
- out.append("{}");
- } else {
- out.append("{\n" + indentString);
- for (size_t n = 0; n < map->size(); n++) {
- out.append(" ");
-
- auto [map_key, map_value] = (*map)[n];
-
- if (!cborPrettyPrintInternal(map_key.get(), out, indent + 2, maxBStrSize,
- mapKeysToNotPrint)) {
- return false;
- }
- out.append(" : ");
- if (map_key->type() == cppbor::TSTR &&
- std::find(mapKeysToNotPrint.begin(), mapKeysToNotPrint.end(),
- map_key->asTstr()->value()) != mapKeysToNotPrint.end()) {
- out.append("<not printed>");
- } else {
- if (!cborPrettyPrintInternal(map_value.get(), out, indent + 2, maxBStrSize,
- mapKeysToNotPrint)) {
- return false;
- }
- }
- out.append(",\n" + indentString);
- }
- out.append("}");
- }
- } break;
-
- case cppbor::SEMANTIC: {
- const cppbor::Semantic* semantic = item->asSemantic();
- snprintf(buf, sizeof(buf), "tag %" PRIu64 " ", semantic->value());
- out.append(buf);
- cborPrettyPrintInternal(semantic->child().get(), out, indent, maxBStrSize,
- mapKeysToNotPrint);
- } break;
-
- case cppbor::SIMPLE:
- const cppbor::Bool* asBool = item->asSimple()->asBool();
- const cppbor::Null* asNull = item->asSimple()->asNull();
- if (asBool != nullptr) {
- out.append(asBool->value() ? "true" : "false");
- } else if (asNull != nullptr) {
- out.append("null");
- } else {
- LOG(ERROR) << "Only boolean/null is implemented for SIMPLE";
- return false;
- }
- break;
- }
-
- return true;
-}
-
-string cborPrettyPrint(const vector<uint8_t>& encodedCbor, size_t maxBStrSize,
- const vector<string>& mapKeysToNotPrint) {
- auto [item, _, message] = cppbor::parse(encodedCbor);
- if (item == nullptr) {
- LOG(ERROR) << "Data to pretty print is not valid CBOR: " << message;
- return "";
- }
-
- string out;
- cborPrettyPrintInternal(item.get(), out, 0, maxBStrSize, mapKeysToNotPrint);
- return out;
-}
-
-// ---------------------------------------------------------------------------
// Crypto functionality / abstraction.
// ---------------------------------------------------------------------------
@@ -2140,7 +1947,7 @@
}
for (size_t n = 0; n < protectedHeaders->size(); n++) {
- auto [keyItem, valueItem] = (*protectedHeaders)[n];
+ auto& [keyItem, valueItem] = (*protectedHeaders)[n];
const cppbor::Int* number = keyItem->asInt();
if (number == nullptr) {
LOG(ERROR) << "Key item in top-level map is not a number";
@@ -2183,7 +1990,7 @@
}
for (size_t n = 0; n < unprotectedHeaders->size(); n++) {
- auto [keyItem, valueItem] = (*unprotectedHeaders)[n];
+ auto& [keyItem, valueItem] = (*unprotectedHeaders)[n];
const cppbor::Int* number = keyItem->asInt();
if (number == nullptr) {
LOG(ERROR) << "Key item in top-level map is not a number";
@@ -2335,9 +2142,9 @@
.add("DeviceAuthentication")
.add(std::move(sessionTranscriptItem))
.add(docType)
- .add(cppbor::Semantic(kSemanticTagEncodedCbor, deviceNameSpacesEncoded));
+ .add(cppbor::SemanticTag(kSemanticTagEncodedCbor, deviceNameSpacesEncoded));
vector<uint8_t> deviceAuthenticationBytes =
- cppbor::Semantic(kSemanticTagEncodedCbor, deviceAuthentication.encode()).encode();
+ cppbor::SemanticTag(kSemanticTagEncodedCbor, deviceAuthentication.encode()).encode();
optional<vector<uint8_t>> calculatedMac =
support::coseMac0(eMacKey, {}, // payload
deviceAuthenticationBytes); // detached content
diff --git a/identity/support/tests/IdentityCredentialSupportTest.cpp b/identity/support/tests/IdentityCredentialSupportTest.cpp
index 509133c..4c9b87a 100644
--- a/identity/support/tests/IdentityCredentialSupportTest.cpp
+++ b/identity/support/tests/IdentityCredentialSupportTest.cpp
@@ -55,99 +55,6 @@
EXPECT_FALSE(support::decodeHex("012"));
}
-TEST(IdentityCredentialSupport, CborPrettyPrint) {
- EXPECT_EQ("'Some text'", support::cborPrettyPrint(cppbor::Tstr("Some text").encode()));
-
- EXPECT_EQ("''", support::cborPrettyPrint(cppbor::Tstr("").encode()));
-
- EXPECT_EQ("{0x01, 0x00, 0x02, 0xf0, 0xff, 0x40}",
- support::cborPrettyPrint(
- cppbor::Bstr(vector<uint8_t>({1, 0, 2, 240, 255, 64})).encode()));
-
- EXPECT_EQ("{}", support::cborPrettyPrint(cppbor::Bstr(vector<uint8_t>()).encode()));
-
- EXPECT_EQ("true", support::cborPrettyPrint(cppbor::Bool(true).encode()));
-
- EXPECT_EQ("false", support::cborPrettyPrint(cppbor::Bool(false).encode()));
-
- EXPECT_EQ("42", support::cborPrettyPrint(cppbor::Uint(42).encode()));
-
- EXPECT_EQ("9223372036854775807", // 0x7fff ffff ffff ffff
- support::cborPrettyPrint(cppbor::Uint(std::numeric_limits<int64_t>::max()).encode()));
-
- EXPECT_EQ("-42", support::cborPrettyPrint(cppbor::Nint(-42).encode()));
-
- EXPECT_EQ("-9223372036854775808", // -0x8000 0000 0000 0000
- support::cborPrettyPrint(cppbor::Nint(std::numeric_limits<int64_t>::min()).encode()));
-}
-
-TEST(IdentityCredentialSupport, CborPrettyPrintCompound) {
- cppbor::Array array = cppbor::Array("foo", "bar", "baz");
- EXPECT_EQ("['foo', 'bar', 'baz', ]", support::cborPrettyPrint(array.encode()));
-
- cppbor::Map map = cppbor::Map().add("foo", 42).add("bar", 43).add("baz", 44);
- EXPECT_EQ(
- "{\n"
- " 'foo' : 42,\n"
- " 'bar' : 43,\n"
- " 'baz' : 44,\n"
- "}",
- support::cborPrettyPrint(map.encode()));
-
- cppbor::Array array2 = cppbor::Array(cppbor::Tstr("Some text"), cppbor::Nint(-42));
- EXPECT_EQ("['Some text', -42, ]", support::cborPrettyPrint(array2.encode()));
-
- cppbor::Map map2 = cppbor::Map().add(42, "foo").add(43, "bar").add(44, "baz");
- EXPECT_EQ(
- "{\n"
- " 42 : 'foo',\n"
- " 43 : 'bar',\n"
- " 44 : 'baz',\n"
- "}",
- support::cborPrettyPrint(map2.encode()));
-
- cppbor::Array deeplyNestedArrays =
- cppbor::Array(cppbor::Array(cppbor::Array("a", "b", "c")),
- cppbor::Array(cppbor::Array("d", "e", cppbor::Array("f", "g"))));
- EXPECT_EQ(
- "[\n"
- " ['a', 'b', 'c', ],\n"
- " [\n 'd',\n"
- " 'e',\n"
- " ['f', 'g', ],\n"
- " ],\n"
- "]",
- support::cborPrettyPrint(deeplyNestedArrays.encode()));
-
- EXPECT_EQ(
- "[\n"
- " {0x0a, 0x0b},\n"
- " 'foo',\n"
- " 42,\n"
- " ['foo', 'bar', 'baz', ],\n"
- " {\n"
- " 'foo' : 42,\n"
- " 'bar' : 43,\n"
- " 'baz' : 44,\n"
- " },\n"
- " {\n"
- " 'deep1' : ['Some text', -42, ],\n"
- " 'deep2' : {\n"
- " 42 : 'foo',\n"
- " 43 : 'bar',\n"
- " 44 : 'baz',\n"
- " },\n"
- " },\n"
- "]",
- support::cborPrettyPrint(cppbor::Array(cppbor::Bstr(vector<uint8_t>{10, 11}),
- cppbor::Tstr("foo"), cppbor::Uint(42),
- std::move(array), std::move(map),
- (cppbor::Map()
- .add("deep1", std::move(array2))
- .add("deep2", std::move(map2))))
- .encode()));
-}
-
TEST(IdentityCredentialSupport, Signatures) {
vector<uint8_t> data = {1, 2, 3};
@@ -219,7 +126,7 @@
ASSERT_EQ(data, payload.value());
// Finally, check that |coseSign1| are the bytes of a valid COSE_Sign1 message
- string out = support::cborPrettyPrint(coseSign1.value());
+ string out = cppbor::prettyPrint(coseSign1.value());
out = replaceLine(out, -2, " [] // Signature Removed");
EXPECT_EQ(
"[\n"
@@ -250,7 +157,7 @@
ASSERT_EQ(0, payload.value().size());
// Finally, check that |coseSign1| are the bytes of a valid COSE_Sign1 message
- string out = support::cborPrettyPrint(coseSign1.value());
+ string out = cppbor::prettyPrint(coseSign1.value());
out = replaceLine(out, -2, " [] // Signature Removed");
EXPECT_EQ(
"[\n"
@@ -411,7 +318,7 @@
"0x86, 0x5c, 0x28, 0x2c, 0xd5, 0xa5, 0x13, 0xff, 0x3b, 0xd1, 0xde, 0x70, 0x5e, 0xbb, "
"0xe2, 0x2d, 0x42, 0xbe, 0x53},\n"
"]",
- support::cborPrettyPrint(mac.value()));
+ cppbor::prettyPrint(mac.value()));
}
TEST(IdentityCredentialSupport, CoseMac0DetachedContent) {
@@ -433,7 +340,7 @@
"0x86, 0x5c, 0x28, 0x2c, 0xd5, 0xa5, 0x13, 0xff, 0x3b, 0xd1, 0xde, 0x70, 0x5e, 0xbb, "
"0xe2, 0x2d, 0x42, 0xbe, 0x53},\n"
"]",
- support::cborPrettyPrint(mac.value()));
+ cppbor::prettyPrint(mac.value()));
}
// Generates a private key in DER format for a small value of 'd'.
@@ -460,8 +367,8 @@
const cppbor::Item* findValueForTstr(const cppbor::Map* map, const string& keyValue) {
// TODO: Need cast until libcppbor's Map::get() is marked as const
- auto [item, found] = ((cppbor::Map*)map)->get(keyValue);
- if (!found) {
+ const auto& item = map->get(keyValue);
+ if (!item) {
return nullptr;
}
return item.get();
@@ -483,12 +390,13 @@
return item->asMap();
}
-const cppbor::Semantic* findSemanticValueForTstr(const cppbor::Map* map, const string& keyValue) {
+const cppbor::SemanticTag* findSemanticValueForTstr(const cppbor::Map* map,
+ const string& keyValue) {
const cppbor::Item* item = findValueForTstr(map, keyValue);
if (item == nullptr) {
return nullptr;
}
- return item->asSemantic();
+ return item->asSemanticTag();
}
const std::string findStringValueForTstr(const cppbor::Map* map, const string& keyValue) {
@@ -576,11 +484,11 @@
auto [sessionEstablishmentItem, _se, _se2] = cppbor::parse(sessionEstablishmentEncoded.value());
const cppbor::Map* sessionEstablishment = sessionEstablishmentItem->asMap();
ASSERT_NE(sessionEstablishment, nullptr);
- const cppbor::Semantic* eReaderKeyBytes =
+ const cppbor::SemanticTag* eReaderKeyBytes =
findSemanticValueForTstr(sessionEstablishment, "eReaderKeyBytes");
ASSERT_NE(eReaderKeyBytes, nullptr);
- ASSERT_EQ(eReaderKeyBytes->value(), 24);
- const cppbor::Bstr* eReaderKeyBstr = eReaderKeyBytes->child()->asBstr();
+ ASSERT_EQ(eReaderKeyBytes->semanticTag(), 24);
+ const cppbor::Bstr* eReaderKeyBstr = eReaderKeyBytes->asBstr();
ASSERT_NE(eReaderKeyBstr, nullptr);
vector<uint8_t> eReaderKeyEncoded = eReaderKeyBstr->value();
// TODO: verify this agrees with ephemeralReaderKeyX and ephemeralReaderKeyY
@@ -605,12 +513,12 @@
// SessionTranscriptBytes = #6.24(bstr .cbor SessionTranscript)
//
cppbor::Array sessionTranscript;
- sessionTranscript.add(cppbor::Semantic(24, deviceEngagementEncoded));
- sessionTranscript.add(cppbor::Semantic(24, eReaderKeyEncoded));
+ sessionTranscript.add(cppbor::SemanticTag(24, deviceEngagementEncoded));
+ sessionTranscript.add(cppbor::SemanticTag(24, eReaderKeyEncoded));
sessionTranscript.add(cppbor::Null());
vector<uint8_t> sessionTranscriptEncoded = sessionTranscript.encode();
vector<uint8_t> sessionTranscriptBytes =
- cppbor::Semantic(24, sessionTranscriptEncoded).encode();
+ cppbor::SemanticTag(24, sessionTranscriptEncoded).encode();
// The expected EMacKey is 4c1ebb8aacc633465390fa44edfdb49cb57f2e079aaa771d812584699c0b97e2
//
@@ -696,11 +604,11 @@
// Dig out the encoded form of DeviceNameSpaces
//
- const cppbor::Semantic* deviceNameSpacesBytes =
+ const cppbor::SemanticTag* deviceNameSpacesBytes =
findSemanticValueForTstr(deviceSigned, "nameSpaces");
ASSERT_NE(deviceNameSpacesBytes, nullptr);
- ASSERT_EQ(deviceNameSpacesBytes->value(), 24);
- const cppbor::Bstr* deviceNameSpacesBstr = deviceNameSpacesBytes->child()->asBstr();
+ ASSERT_EQ(deviceNameSpacesBytes->semanticTag(), 24);
+ const cppbor::Bstr* deviceNameSpacesBstr = deviceNameSpacesBytes->asBstr();
ASSERT_NE(deviceNameSpacesBstr, nullptr);
vector<uint8_t> deviceNameSpacesEncoded = deviceNameSpacesBstr->value();
diff --git a/neuralnetworks/aidl/Android.bp b/neuralnetworks/aidl/Android.bp
index b1860e2..ebf4654 100644
--- a/neuralnetworks/aidl/Android.bp
+++ b/neuralnetworks/aidl/Android.bp
@@ -16,6 +16,7 @@
stability: "vintf",
imports: [
"android.hardware.common",
+ "android.hardware.graphics.common",
],
backend: {
java: {
diff --git a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl
index 8207b25..37fa102 100644
--- a/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl
+++ b/neuralnetworks/aidl/aidl_api/android.hardware.neuralnetworks/current/android/hardware/neuralnetworks/Memory.aidl
@@ -33,8 +33,8 @@
package android.hardware.neuralnetworks;
@VintfStability
-parcelable Memory {
- android.hardware.common.NativeHandle handle;
- long size;
- String name;
+union Memory {
+ android.hardware.common.Ashmem ashmem;
+ android.hardware.common.MappableFile mappableFile;
+ android.hardware.graphics.common.HardwareBuffer hardwareBuffer;
}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl
index 861b6f0..df015ca 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/FusedActivationFunc.aidl
@@ -22,8 +22,20 @@
@VintfStability
@Backing(type="int")
enum FusedActivationFunc {
+ /**
+ * No activation.
+ */
NONE,
+ /**
+ * ReLU(x) = max(0, x)
+ */
RELU,
+ /**
+ * ReLU1(x) = min(1, max(-1, x))
+ */
RELU1,
+ /**
+ * ReLU6(x) = min(6, max(0, x))
+ */
RELU6,
}
diff --git a/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl b/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl
index 870f0ae..244ac87 100644
--- a/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl
+++ b/neuralnetworks/aidl/android/hardware/neuralnetworks/Memory.aidl
@@ -15,16 +15,26 @@
*/
package android.hardware.neuralnetworks;
-import android.hardware.common.NativeHandle;
-import android.os.ParcelFileDescriptor;
+
+import android.hardware.common.Ashmem;
+import android.hardware.common.MappableFile;
+import android.hardware.graphics.common.HardwareBuffer;
/**
- * A type that is used to pass pieces of shared memory between processes.
- * The type structure mimics hidl_memory type from HIDL.
+ * The different types of memory that can be shared across processes.
*/
@VintfStability
-parcelable Memory {
- NativeHandle handle;
- long size;
- String name;
+union Memory {
+ /**
+ * Ashmem hidl_memory type from HIDL.
+ */
+ Ashmem ashmem;
+ /**
+ * File that can be mapped.
+ */
+ MappableFile mappableFile;
+ /**
+ * AIDL representation of AHardwareBuffer.
+ */
+ HardwareBuffer hardwareBuffer;
}
diff --git a/neuralnetworks/aidl/utils/Android.bp b/neuralnetworks/aidl/utils/Android.bp
index ad961cf..0ccc711 100644
--- a/neuralnetworks/aidl/utils/Android.bp
+++ b/neuralnetworks/aidl/utils/Android.bp
@@ -31,6 +31,8 @@
export_include_dirs: ["include"],
cflags: ["-Wthread-safety"],
static_libs: [
+ "android.hardware.graphics.common-V2-ndk_platform",
+ "libaidlcommonsupport",
"libarect",
"neuralnetworks_types",
"neuralnetworks_utils_hal_common",
@@ -51,7 +53,9 @@
],
static_libs: [
"android.hardware.common-V2-ndk_platform",
+ "android.hardware.graphics.common-V2-ndk_platform",
"android.hardware.neuralnetworks-V1-ndk_platform",
+ "libaidlcommonsupport",
"libgmock",
"libneuralnetworks_common",
"neuralnetworks_types",
diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h
new file mode 100644
index 0000000..e66507a
--- /dev/null
+++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/InvalidDevice.h
@@ -0,0 +1,70 @@
+/*
+ * 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.
+ */
+
+#pragma once
+
+#include <aidl/android/hardware/neuralnetworks/BnBuffer.h>
+#include <aidl/android/hardware/neuralnetworks/BnDevice.h>
+#include <aidl/android/hardware/neuralnetworks/BnPreparedModel.h>
+#include <android/binder_auto_utils.h>
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace aidl::android::hardware::neuralnetworks {
+
+class InvalidDevice : public BnDevice {
+ public:
+ static std::shared_ptr<InvalidDevice> create();
+
+ InvalidDevice(Capabilities capabilities, const NumberOfCacheFiles& numberOfCacheFiles,
+ std::vector<Extension> extensions, DeviceType deviceType,
+ std::string versionString);
+
+ ndk::ScopedAStatus allocate(const BufferDesc& desc,
+ const std::vector<IPreparedModelParcel>& preparedModels,
+ const std::vector<BufferRole>& inputRoles,
+ const std::vector<BufferRole>& outputRoles,
+ DeviceBuffer* deviceBuffer) override;
+ ndk::ScopedAStatus getCapabilities(Capabilities* capabilities) override;
+ ndk::ScopedAStatus getNumberOfCacheFilesNeeded(NumberOfCacheFiles* numberOfCacheFiles) override;
+ ndk::ScopedAStatus getSupportedExtensions(std::vector<Extension>* extensions) override;
+ ndk::ScopedAStatus getSupportedOperations(const Model& model,
+ std::vector<bool>* supportedOperations) override;
+ ndk::ScopedAStatus getType(DeviceType* deviceType) override;
+ ndk::ScopedAStatus getVersionString(std::string* versionString) override;
+ ndk::ScopedAStatus prepareModel(
+ const Model& model, ExecutionPreference preference, Priority priority, int64_t deadline,
+ const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+ const std::vector<ndk::ScopedFileDescriptor>& dataCache,
+ const std::vector<uint8_t>& token,
+ const std::shared_ptr<IPreparedModelCallback>& callback) override;
+ ndk::ScopedAStatus prepareModelFromCache(
+ int64_t deadline, const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+ const std::vector<ndk::ScopedFileDescriptor>& dataCache,
+ const std::vector<uint8_t>& token,
+ const std::shared_ptr<IPreparedModelCallback>& callback) override;
+
+ private:
+ const Capabilities kCapabilities;
+ const NumberOfCacheFiles kNumberOfCacheFiles;
+ const std::vector<Extension> kExtensions;
+ const DeviceType kDeviceType;
+ const std::string kVersionString;
+};
+
+} // namespace aidl::android::hardware::neuralnetworks
diff --git a/neuralnetworks/aidl/utils/src/Conversions.cpp b/neuralnetworks/aidl/utils/src/Conversions.cpp
index d5f7f81..93ac51c 100644
--- a/neuralnetworks/aidl/utils/src/Conversions.cpp
+++ b/neuralnetworks/aidl/utils/src/Conversions.cpp
@@ -16,8 +16,13 @@
#include "Conversions.h"
+#include <aidl/android/hardware/common/Ashmem.h>
+#include <aidl/android/hardware/common/MappableFile.h>
#include <aidl/android/hardware/common/NativeHandle.h>
+#include <aidl/android/hardware/graphics/common/HardwareBuffer.h>
+#include <aidlcommonsupport/NativeHandle.h>
#include <android-base/logging.h>
+#include <android-base/mapped_file.h>
#include <android-base/unique_fd.h>
#include <android/binder_auto_utils.h>
#include <android/hardware_buffer.h>
@@ -125,28 +130,17 @@
using UniqueNativeHandle = std::unique_ptr<native_handle_t, NativeHandleDeleter>;
-static GeneralResult<UniqueNativeHandle> nativeHandleFromAidlHandle(const NativeHandle& handle) {
- std::vector<base::unique_fd> fds;
- fds.reserve(handle.fds.size());
- for (const auto& fd : handle.fds) {
- auto duplicatedFd = NN_TRY(dupFd(fd.get()));
- fds.emplace_back(duplicatedFd.release());
+GeneralResult<UniqueNativeHandle> nativeHandleFromAidlHandle(const NativeHandle& handle) {
+ auto nativeHandle = UniqueNativeHandle(dupFromAidl(handle));
+ if (nativeHandle.get() == nullptr) {
+ return NN_ERROR() << "android::dupFromAidl failed to convert the common::NativeHandle to a "
+ "native_handle_t";
}
-
- 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";
+ if (!std::all_of(nativeHandle->data + 0, nativeHandle->data + nativeHandle->numFds,
+ [](int fd) { return fd >= 0; })) {
+ return NN_ERROR() << "android::dupFromAidl returned an invalid native_handle_t";
}
- 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);
+ return nativeHandle;
}
} // anonymous namespace
@@ -353,67 +347,66 @@
return measureTiming ? MeasureTiming::YES : MeasureTiming::NO;
}
-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";
- if (memory.size > std::numeric_limits<size_t>::max()) {
- return NN_ERROR() << "Memory: size must be <= std::numeric_limits<size_t>::max()";
- }
+ using Tag = aidl_hal::Memory::Tag;
+ switch (memory.getTag()) {
+ case Tag::ashmem: {
+ const auto& ashmem = memory.get<Tag::ashmem>();
+ VERIFY_NON_NEGATIVE(ashmem.size) << "Memory size must not be negative";
+ if (ashmem.size > std::numeric_limits<size_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<size_t>(memory.size),
- .name = memory.name,
- });
- }
+ auto handle = Memory::Ashmem{
+ .fd = NN_TRY(dupFd(ashmem.fd.get())),
+ .size = static_cast<size_t>(ashmem.size),
+ };
+ return std::make_shared<const Memory>(Memory{.handle = std::move(handle)});
+ }
+ case Tag::mappableFile: {
+ const auto& mappableFile = memory.get<Tag::mappableFile>();
+ VERIFY_NON_NEGATIVE(mappableFile.length) << "Memory size must not be negative";
+ VERIFY_NON_NEGATIVE(mappableFile.offset) << "Memory offset must not be negative";
+ if (mappableFile.length > std::numeric_limits<size_t>::max()) {
+ return NN_ERROR() << "Memory: size must be <= std::numeric_limits<size_t>::max()";
+ }
+ if (mappableFile.offset > std::numeric_limits<size_t>::max()) {
+ return NN_ERROR() << "Memory: offset must be <= std::numeric_limits<size_t>::max()";
+ }
- 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 size_t size = static_cast<size_t>(mappableFile.length);
+ const int prot = mappableFile.prot;
+ const int fd = mappableFile.fd.get();
+ const size_t offset = static_cast<size_t>(mappableFile.offset);
- const UniqueNativeHandle handle = NN_TRY(nativeHandleFromAidlHandle(memory.handle));
- const native_handle_t* nativeHandle = handle.get();
+ return createSharedMemoryFromFd(size, prot, fd, offset);
+ }
+ case Tag::hardwareBuffer: {
+ const auto& hardwareBuffer = memory.get<Tag::hardwareBuffer>();
- // 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;
+ const UniqueNativeHandle handle =
+ NN_TRY(nativeHandleFromAidlHandle(hardwareBuffer.handle));
+ const native_handle_t* nativeHandle = handle.get();
+
+ const AHardwareBuffer_Desc desc{
+ .width = static_cast<uint32_t>(hardwareBuffer.description.width),
+ .height = static_cast<uint32_t>(hardwareBuffer.description.height),
+ .layers = static_cast<uint32_t>(hardwareBuffer.description.layers),
+ .format = static_cast<uint32_t>(hardwareBuffer.description.format),
+ .usage = static_cast<uint64_t>(hardwareBuffer.description.usage),
+ .stride = static_cast<uint32_t>(hardwareBuffer.description.stride),
+ };
+ AHardwareBuffer* ahwb = nullptr;
+ const status_t status = AHardwareBuffer_createFromHandle(
+ &desc, nativeHandle, AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, &ahwb);
+ if (status != NO_ERROR) {
+ return NN_ERROR() << "createFromHandle failed";
+ }
+
+ return createSharedMemoryFromAHWB(ahwb, /*takeOwnership=*/true);
}
}
- 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<size_t>(memory.size),
- .name = memory.name,
- });
+ return NN_ERROR() << "Unrecognized Memory::Tag: " << memory.getTag();
}
GeneralResult<Timing> unvalidatedConvert(const aidl_hal::Timing& timing) {
@@ -645,20 +638,95 @@
template <class... Ts>
overloaded(Ts...)->overloaded<Ts...>;
-static nn::GeneralResult<common::NativeHandle> aidlHandleFromNativeHandle(
- const native_handle_t& handle) {
- common::NativeHandle aidlNativeHandle;
+nn::GeneralResult<common::NativeHandle> aidlHandleFromNativeHandle(
+ const native_handle_t& nativeHandle) {
+ auto handle = ::android::dupToAidl(&nativeHandle);
+ if (!std::all_of(handle.fds.begin(), handle.fds.end(),
+ [](const ndk::ScopedFileDescriptor& fd) { return fd.get() >= 0; })) {
+ return NN_ERROR() << "android::dupToAidl returned an invalid common::NativeHandle";
+ }
+ return handle;
+}
- aidlNativeHandle.fds.reserve(handle.numFds);
- for (int i = 0; i < handle.numFds; ++i) {
- auto duplicatedFd = NN_TRY(nn::dupFd(handle.data[i]));
- aidlNativeHandle.fds.emplace_back(duplicatedFd.release());
+nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::Ashmem& memory) {
+ if constexpr (std::numeric_limits<size_t>::max() > std::numeric_limits<int64_t>::max()) {
+ if (memory.size > std::numeric_limits<int64_t>::max()) {
+ return (
+ NN_ERROR()
+ << "Memory::Ashmem: size must be <= std::numeric_limits<int64_t>::max()")
+ .
+ operator nn::GeneralResult<Memory>();
+ }
}
- aidlNativeHandle.ints = std::vector<int>(&handle.data[handle.numFds],
- &handle.data[handle.numFds + handle.numInts]);
+ auto fd = NN_TRY(nn::dupFd(memory.fd));
+ auto handle = common::Ashmem{
+ .fd = ndk::ScopedFileDescriptor(fd.release()),
+ .size = static_cast<int64_t>(memory.size),
+ };
+ return Memory::make<Memory::Tag::ashmem>(std::move(handle));
+}
- return aidlNativeHandle;
+nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::Fd& memory) {
+ if constexpr (std::numeric_limits<size_t>::max() > std::numeric_limits<int64_t>::max()) {
+ if (memory.size > std::numeric_limits<int64_t>::max()) {
+ return (NN_ERROR() << "Memory::Fd: size must be <= std::numeric_limits<int64_t>::max()")
+ .
+ operator nn::GeneralResult<Memory>();
+ }
+ if (memory.offset > std::numeric_limits<int64_t>::max()) {
+ return (
+ NN_ERROR()
+ << "Memory::Fd: offset must be <= std::numeric_limits<int64_t>::max()")
+ .
+ operator nn::GeneralResult<Memory>();
+ }
+ }
+
+ auto fd = NN_TRY(nn::dupFd(memory.fd));
+ auto handle = common::MappableFile{
+ .length = static_cast<int64_t>(memory.size),
+ .prot = memory.prot,
+ .fd = ndk::ScopedFileDescriptor(fd.release()),
+ .offset = static_cast<int64_t>(memory.offset),
+ };
+ return Memory::make<Memory::Tag::mappableFile>(std::move(handle));
+}
+
+nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::HardwareBuffer& memory) {
+ const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(memory.handle.get());
+ if (nativeHandle == nullptr) {
+ return (NN_ERROR() << "unvalidatedConvert failed because AHardwareBuffer_getNativeHandle "
+ "returned nullptr")
+ .
+ operator nn::GeneralResult<Memory>();
+ }
+
+ auto handle = NN_TRY(aidlHandleFromNativeHandle(*nativeHandle));
+
+ AHardwareBuffer_Desc desc;
+ AHardwareBuffer_describe(memory.handle.get(), &desc);
+
+ const auto description = graphics::common::HardwareBufferDescription{
+ .width = static_cast<int32_t>(desc.width),
+ .height = static_cast<int32_t>(desc.height),
+ .layers = static_cast<int32_t>(desc.layers),
+ .format = static_cast<graphics::common::PixelFormat>(desc.format),
+ .usage = static_cast<graphics::common::BufferUsage>(desc.usage),
+ .stride = static_cast<int32_t>(desc.stride),
+ };
+
+ auto hardwareBuffer = graphics::common::HardwareBuffer{
+ .description = std::move(description),
+ .handle = std::move(handle),
+ };
+ return Memory::make<Memory::Tag::hardwareBuffer>(std::move(hardwareBuffer));
+}
+
+nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::Unknown& /*memory*/) {
+ return (NN_ERROR() << "Unable to convert Unknown memory type")
+ .
+ operator nn::GeneralResult<Memory>();
}
} // namespace
@@ -693,41 +761,12 @@
}
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 (memory == nullptr) {
+ return (NN_ERROR() << "Unable to convert nullptr memory")
+ .
+ operator nn::GeneralResult<Memory>();
}
- 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(aidlHandleFromNativeHandle(*nativeHandle)),
- .size = static_cast<int64_t>(memory->size),
- .name = memory->name,
- };
+ return std::visit([](const auto& x) { return unvalidatedConvert(x); }, memory->handle);
}
nn::GeneralResult<ErrorStatus> unvalidatedConvert(const nn::ErrorStatus& errorStatus) {
diff --git a/neuralnetworks/aidl/utils/src/InvalidDevice.cpp b/neuralnetworks/aidl/utils/src/InvalidDevice.cpp
new file mode 100644
index 0000000..c9d9955
--- /dev/null
+++ b/neuralnetworks/aidl/utils/src/InvalidDevice.cpp
@@ -0,0 +1,179 @@
+/*
+ * 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 "InvalidDevice"
+
+#include "InvalidDevice.h"
+
+#include <aidl/android/hardware/neuralnetworks/BnBuffer.h>
+#include <aidl/android/hardware/neuralnetworks/BnDevice.h>
+#include <aidl/android/hardware/neuralnetworks/BnPreparedModel.h>
+#include <android/binder_auto_utils.h>
+
+#include "Conversions.h"
+#include "Utils.h"
+
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace aidl::android::hardware::neuralnetworks {
+namespace {
+
+ndk::ScopedAStatus toAStatus(ErrorStatus errorStatus, const std::string& errorMessage) {
+ if (errorStatus == ErrorStatus::NONE) {
+ return ndk::ScopedAStatus::ok();
+ }
+ return ndk::ScopedAStatus::fromServiceSpecificErrorWithMessage(
+ static_cast<int32_t>(errorStatus), errorMessage.c_str());
+}
+
+} // namespace
+
+std::shared_ptr<InvalidDevice> InvalidDevice::create() {
+ constexpr auto perf = PerformanceInfo{
+ .execTime = std::numeric_limits<float>::max(),
+ .powerUsage = std::numeric_limits<float>::max(),
+ };
+ auto capabilities = Capabilities{
+ .relaxedFloat32toFloat16PerformanceScalar = perf,
+ .relaxedFloat32toFloat16PerformanceTensor = perf,
+ .operandPerformance = {},
+ .ifPerformance = perf,
+ .whilePerformance = perf,
+ };
+ constexpr auto numberOfCacheFiles = NumberOfCacheFiles{
+ .numModelCache = 0,
+ .numDataCache = 0,
+ };
+ std::vector<Extension> extensions{};
+ constexpr auto deviceType = DeviceType::OTHER;
+ std::string versionString = "invalid";
+
+ return ndk::SharedRefBase::make<InvalidDevice>(std::move(capabilities), numberOfCacheFiles,
+ std::move(extensions), deviceType,
+ std::move(versionString));
+}
+
+InvalidDevice::InvalidDevice(Capabilities capabilities,
+ const NumberOfCacheFiles& numberOfCacheFiles,
+ std::vector<Extension> extensions, DeviceType deviceType,
+ std::string versionString)
+ : kCapabilities(std::move(capabilities)),
+ kNumberOfCacheFiles(numberOfCacheFiles),
+ kExtensions(std::move(extensions)),
+ kDeviceType(deviceType),
+ kVersionString(std::move(versionString)) {}
+
+ndk::ScopedAStatus InvalidDevice::allocate(
+ const BufferDesc& /*desc*/, const std::vector<IPreparedModelParcel>& /*preparedModels*/,
+ const std::vector<BufferRole>& /*inputRoles*/,
+ const std::vector<BufferRole>& /*outputRoles*/, DeviceBuffer* /*deviceBuffer*/) {
+ return toAStatus(ErrorStatus::GENERAL_FAILURE, "InvalidDevice");
+}
+
+ndk::ScopedAStatus InvalidDevice::getCapabilities(Capabilities* capabilities) {
+ *capabilities = kCapabilities;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::getNumberOfCacheFilesNeeded(
+ NumberOfCacheFiles* numberOfCacheFiles) {
+ *numberOfCacheFiles = kNumberOfCacheFiles;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::getSupportedExtensions(std::vector<Extension>* extensions) {
+ *extensions = kExtensions;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::getSupportedOperations(const Model& model,
+ std::vector<bool>* supportedOperations) {
+ if (const auto result = utils::validate(model); !result.ok()) {
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT, result.error());
+ }
+ *supportedOperations = std::vector<bool>(model.main.operations.size(), false);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::getType(DeviceType* deviceType) {
+ *deviceType = kDeviceType;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::getVersionString(std::string* versionString) {
+ *versionString = kVersionString;
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::prepareModel(
+ const Model& model, ExecutionPreference preference, Priority priority, int64_t deadline,
+ const std::vector<ndk::ScopedFileDescriptor>& modelCache,
+ const std::vector<ndk::ScopedFileDescriptor>& dataCache, const std::vector<uint8_t>& token,
+ const std::shared_ptr<IPreparedModelCallback>& callback) {
+ if (callback.get() == nullptr) {
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT,
+ "invalid callback passed to InvalidDevice::prepareModel");
+ }
+ if (const auto result = utils::validate(model); !result.ok()) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT, result.error());
+ }
+ if (const auto result = utils::validate(preference); !result.ok()) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT, result.error());
+ }
+ if (const auto result = utils::validate(priority); !result.ok()) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT, result.error());
+ }
+ if (deadline < -1) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT,
+ "Invalid deadline " + std::to_string(deadline));
+ }
+ if (modelCache.size() != static_cast<size_t>(kNumberOfCacheFiles.numModelCache)) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT,
+ "Invalid modelCache, size = " + std::to_string(modelCache.size()));
+ }
+ if (dataCache.size() != static_cast<size_t>(kNumberOfCacheFiles.numDataCache)) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(ErrorStatus::INVALID_ARGUMENT,
+ "Invalid modelCache, size = " + std::to_string(dataCache.size()));
+ }
+ if (token.size() != IDevice::BYTE_SIZE_OF_CACHE_TOKEN) {
+ callback->notify(ErrorStatus::INVALID_ARGUMENT, nullptr);
+ return toAStatus(
+ ErrorStatus::INVALID_ARGUMENT,
+ "Invalid cache token, size = " + std::to_string(IDevice::BYTE_SIZE_OF_CACHE_TOKEN));
+ }
+ callback->notify(ErrorStatus::GENERAL_FAILURE, nullptr);
+ return ndk::ScopedAStatus::ok();
+}
+
+ndk::ScopedAStatus InvalidDevice::prepareModelFromCache(
+ int64_t /*deadline*/, const std::vector<ndk::ScopedFileDescriptor>& /*modelCache*/,
+ const std::vector<ndk::ScopedFileDescriptor>& /*dataCache*/,
+ const std::vector<uint8_t>& /*token*/,
+ const std::shared_ptr<IPreparedModelCallback>& callback) {
+ callback->notify(ErrorStatus::GENERAL_FAILURE, nullptr);
+ return toAStatus(ErrorStatus::GENERAL_FAILURE, "InvalidDevice");
+}
+
+} // namespace aidl::android::hardware::neuralnetworks
diff --git a/neuralnetworks/aidl/utils/src/Service.cpp b/neuralnetworks/aidl/utils/src/Service.cpp
index 511de55..ac182a2 100644
--- a/neuralnetworks/aidl/utils/src/Service.cpp
+++ b/neuralnetworks/aidl/utils/src/Service.cpp
@@ -16,6 +16,7 @@
#include "Service.h"
+#include <AndroidVersionUtil.h>
#include <android/binder_auto_utils.h>
#include <android/binder_manager.h>
#include <android/binder_process.h>
@@ -35,13 +36,23 @@
hal::utils::ResilientDevice::Factory makeDevice =
[instanceName,
name = std::move(fullName)](bool blocking) -> nn::GeneralResult<nn::SharedDevice> {
- const auto& getService =
- blocking ? AServiceManager_getService : AServiceManager_checkService;
+ std::add_pointer_t<AIBinder*(const char*)> getService;
+ if (blocking) {
+ if (__builtin_available(android __NNAPI_AIDL_MIN_ANDROID_API__, *)) {
+ getService = AServiceManager_waitForService;
+ } else {
+ getService = AServiceManager_getService;
+ }
+ } else {
+ getService = AServiceManager_checkService;
+ }
+
auto service = IDevice::fromBinder(ndk::SpAIBinder(getService(name.c_str())));
if (service == nullptr) {
- return NN_ERROR() << (blocking ? "AServiceManager_getService"
- : "AServiceManager_checkService")
- << " returned nullptr";
+ return NN_ERROR()
+ << (blocking ? "AServiceManager_waitForService (or AServiceManager_getService)"
+ : "AServiceManager_checkService")
+ << " returned nullptr";
}
ABinderProcess_startThreadPool();
return Device::create(instanceName, std::move(service));
diff --git a/neuralnetworks/aidl/utils/src/Utils.cpp b/neuralnetworks/aidl/utils/src/Utils.cpp
index 95516c8..03407be 100644
--- a/neuralnetworks/aidl/utils/src/Utils.cpp
+++ b/neuralnetworks/aidl/utils/src/Utils.cpp
@@ -16,12 +16,20 @@
#include "Utils.h"
+#include <aidl/android/hardware/common/Ashmem.h>
+#include <aidl/android/hardware/common/MappableFile.h>
+#include <aidl/android/hardware/graphics/common/HardwareBuffer.h>
+#include <android/binder_auto_utils.h>
#include <android/binder_status.h>
#include <nnapi/Result.h>
+#include <nnapi/SharedMemory.h>
namespace aidl::android::hardware::neuralnetworks::utils {
namespace {
+nn::GeneralResult<ndk::ScopedFileDescriptor> clone(const ndk::ScopedFileDescriptor& fd);
+using utils::clone;
+
template <typename Type>
nn::GeneralResult<std::vector<Type>> cloneVec(const std::vector<Type>& arguments) {
std::vector<Type> clonedObjects;
@@ -37,24 +45,52 @@
return cloneVec(arguments);
}
+nn::GeneralResult<ndk::ScopedFileDescriptor> clone(const ndk::ScopedFileDescriptor& fd) {
+ auto duplicatedFd = NN_TRY(nn::dupFd(fd.get()));
+ return ndk::ScopedFileDescriptor(duplicatedFd.release());
+}
+
+nn::GeneralResult<common::NativeHandle> clone(const common::NativeHandle& handle) {
+ return common::NativeHandle{
+ .fds = NN_TRY(cloneVec(handle.fds)),
+ .ints = handle.ints,
+ };
+}
+
} // namespace
nn::GeneralResult<Memory> clone(const Memory& memory) {
- common::NativeHandle nativeHandle;
- nativeHandle.ints = memory.handle.ints;
- nativeHandle.fds.reserve(memory.handle.fds.size());
- for (const auto& fd : memory.handle.fds) {
- const int newFd = dup(fd.get());
- if (newFd < 0) {
- return NN_ERROR() << "Couldn't dup a file descriptor";
+ switch (memory.getTag()) {
+ case Memory::Tag::ashmem: {
+ const auto& ashmem = memory.get<Memory::Tag::ashmem>();
+ auto handle = common::Ashmem{
+ .fd = NN_TRY(clone(ashmem.fd)),
+ .size = ashmem.size,
+ };
+ return Memory::make<Memory::Tag::ashmem>(std::move(handle));
}
- nativeHandle.fds.emplace_back(newFd);
+ case Memory::Tag::mappableFile: {
+ const auto& memFd = memory.get<Memory::Tag::mappableFile>();
+ auto handle = common::MappableFile{
+ .length = memFd.length,
+ .prot = memFd.prot,
+ .fd = NN_TRY(clone(memFd.fd)),
+ .offset = memFd.offset,
+ };
+ return Memory::make<Memory::Tag::mappableFile>(std::move(handle));
+ }
+ case Memory::Tag::hardwareBuffer: {
+ const auto& hardwareBuffer = memory.get<Memory::Tag::hardwareBuffer>();
+ auto handle = graphics::common::HardwareBuffer{
+ .description = hardwareBuffer.description,
+ .handle = NN_TRY(clone(hardwareBuffer.handle)),
+ };
+ return Memory::make<Memory::Tag::hardwareBuffer>(std::move(handle));
+ }
}
- return Memory{
- .handle = std::move(nativeHandle),
- .size = memory.size,
- .name = memory.name,
- };
+ return (NN_ERROR() << "Unrecognized Memory::Tag: " << memory.getTag())
+ .
+ operator nn::GeneralResult<Memory>();
}
nn::GeneralResult<RequestMemoryPool> clone(const RequestMemoryPool& requestPool) {
diff --git a/neuralnetworks/aidl/vts/functional/Android.bp b/neuralnetworks/aidl/vts/functional/Android.bp
index 7804c2a..d5b150a 100644
--- a/neuralnetworks/aidl/vts/functional/Android.bp
+++ b/neuralnetworks/aidl/vts/functional/Android.bp
@@ -50,9 +50,11 @@
],
static_libs: [
"android.hardware.common-V2-ndk_platform",
+ "android.hardware.graphics.common-V2-ndk_platform",
"android.hardware.neuralnetworks-V1-ndk_platform",
"android.hidl.allocator@1.0",
"android.hidl.memory@1.0",
+ "libaidlcommonsupport",
"libgmock",
"libhidlmemory",
"libneuralnetworks_generated_test_harness",
diff --git a/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp b/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp
index 596f8ae..e8313f1 100644
--- a/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp
+++ b/neuralnetworks/aidl/vts/functional/MemoryDomainTests.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "neuralnetworks_aidl_hal_test"
+#include <aidl/android/hardware/graphics/common/PixelFormat.h>
#include <android-base/logging.h>
#include <android/binder_auto_utils.h>
#include <android/binder_interface_utils.h>
@@ -659,10 +660,26 @@
return allocateBuffer(preparedModel, inputIndexes, outputIndexes, {});
}
+ size_t getSize(const Memory& memory) {
+ switch (memory.getTag()) {
+ case Memory::Tag::ashmem:
+ return memory.get<Memory::Tag::ashmem>().size;
+ case Memory::Tag::mappableFile:
+ return memory.get<Memory::Tag::mappableFile>().length;
+ case Memory::Tag::hardwareBuffer: {
+ const auto& hardwareBuffer = memory.get<Memory::Tag::hardwareBuffer>();
+ const bool isBlob =
+ hardwareBuffer.description.format == graphics::common::PixelFormat::BLOB;
+ return isBlob ? hardwareBuffer.description.width : 0;
+ }
+ }
+ return 0;
+ }
+
Memory allocateSharedMemory(uint32_t size) {
const auto sharedMemory = nn::createSharedMemory(size).value();
auto memory = utils::convert(sharedMemory).value();
- EXPECT_EQ(memory.size, size);
+ EXPECT_EQ(getSize(memory), size);
return memory;
}
@@ -690,7 +707,7 @@
void initializeDeviceMemory(const std::shared_ptr<IBuffer>& buffer) {
Memory memory = allocateSharedMemory(kTestOperandDataSize);
- ASSERT_EQ(memory.size, kTestOperandDataSize);
+ ASSERT_EQ(getSize(memory), kTestOperandDataSize);
testCopyFrom(buffer, memory, utils::toSigned(kTestOperand.dimensions).value(),
ErrorStatus::NONE);
}
diff --git a/neuralnetworks/aidl/vts/functional/ValidateModel.cpp b/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
index 94d3daf..698c054 100644
--- a/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
+++ b/neuralnetworks/aidl/vts/functional/ValidateModel.cpp
@@ -259,12 +259,16 @@
size_t sizeForBinder(const Memory& memory) {
// This is just a guess.
- size_t size = 0;
- const NativeHandle& handle = memory.handle;
- size += sizeof(decltype(handle.fds)::value_type) * handle.fds.size();
- size += sizeof(decltype(handle.ints)::value_type) * handle.ints.size();
- size += sizeForBinder(memory.name);
- size += sizeof(memory);
+ size_t size = sizeof(Memory);
+
+ // Only hardwareBuffer type memory has dynamic memory that needs to be accounted for (in the
+ // form of a NativeHandle type). The other other types of memory (MappableFile, Ashmem) use a
+ // single file descriptor (with metadata) instead.
+ if (memory.getTag() == Memory::Tag::hardwareBuffer) {
+ const NativeHandle& handle = memory.get<Memory::Tag::hardwareBuffer>().handle;
+ size += sizeof(decltype(handle.fds)::value_type) * handle.fds.size();
+ size += sizeof(decltype(handle.ints)::value_type) * handle.ints.size();
+ }
return size;
}
diff --git a/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp b/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp
index 0c3a196..ee7cf89 100644
--- a/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp
+++ b/neuralnetworks/aidl/vts/functional/VtsHalNeuralnetworks.cpp
@@ -94,7 +94,7 @@
}
static NamedDevice makeNamedDevice(const std::string& name) {
- ndk::SpAIBinder binder(AServiceManager_getService(name.c_str()));
+ ndk::SpAIBinder binder(AServiceManager_waitForService(name.c_str()));
return {name, IDevice::fromBinder(binder)};
}
diff --git a/neuralnetworks/utils/common/src/CommonUtils.cpp b/neuralnetworks/utils/common/src/CommonUtils.cpp
index 924ecb2..4d26795 100644
--- a/neuralnetworks/utils/common/src/CommonUtils.cpp
+++ b/neuralnetworks/utils/common/src/CommonUtils.cpp
@@ -89,6 +89,59 @@
});
}
+nn::GeneralResult<hidl_handle> createNativeHandleFrom(base::unique_fd fd,
+ const std::vector<int32_t>& ints) {
+ constexpr size_t kIntMax = std::numeric_limits<int>::max();
+ CHECK_LE(ints.size(), kIntMax);
+ native_handle_t* nativeHandle = native_handle_create(1, static_cast<int>(ints.size()));
+ if (nativeHandle == nullptr) {
+ return NN_ERROR() << "Failed to create native_handle";
+ }
+
+ nativeHandle->data[0] = fd.release();
+ std::copy(ints.begin(), ints.end(), nativeHandle->data + 1);
+
+ hidl_handle handle;
+ handle.setTo(nativeHandle, /*shouldOwn=*/true);
+ return handle;
+}
+
+nn::GeneralResult<hidl_memory> createHidlMemoryFrom(const nn::Memory::Ashmem& memory) {
+ auto fd = NN_TRY(nn::dupFd(memory.fd));
+ auto handle = NN_TRY(createNativeHandleFrom(std::move(fd), {}));
+ return hidl_memory("ashmem", std::move(handle), memory.size);
+}
+
+nn::GeneralResult<hidl_memory> createHidlMemoryFrom(const nn::Memory::Fd& memory) {
+ auto fd = NN_TRY(nn::dupFd(memory.fd));
+
+ const auto [lowOffsetBits, highOffsetBits] = nn::getIntsFromOffset(memory.offset);
+ const std::vector<int> ints = {memory.prot, lowOffsetBits, highOffsetBits};
+
+ auto handle = NN_TRY(createNativeHandleFrom(std::move(fd), ints));
+ return hidl_memory("mmap_fd", std::move(handle), memory.size);
+}
+
+nn::GeneralResult<hidl_memory> createHidlMemoryFrom(const nn::Memory::HardwareBuffer& memory) {
+ const auto* ahwb = memory.handle.get();
+ AHardwareBuffer_Desc bufferDesc;
+ AHardwareBuffer_describe(ahwb, &bufferDesc);
+
+ const bool isBlob = bufferDesc.format == AHARDWAREBUFFER_FORMAT_BLOB;
+ const size_t size = isBlob ? bufferDesc.width : 0;
+ const char* const name = isBlob ? "hardware_buffer_blob" : "hardware_buffer";
+
+ const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(ahwb);
+ const hidl_handle hidlHandle(nativeHandle);
+ hidl_handle copiedHandle(hidlHandle);
+
+ return hidl_memory(name, std::move(copiedHandle), size);
+}
+
+nn::GeneralResult<hidl_memory> createHidlMemoryFrom(const nn::Memory::Unknown& memory) {
+ return hidl_memory(memory.name, NN_TRY(hidlHandleFromSharedHandle(memory.handle)), memory.size);
+}
+
} // anonymous namespace
nn::Capabilities::OperandPerformanceTable makeQuantized8PerformanceConsistentWithP(
@@ -255,27 +308,7 @@
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);
+ return std::visit([](const auto& x) { return createHidlMemoryFrom(x); }, memory->handle);
}
static uint32_t roundUpToMultiple(uint32_t value, uint32_t multiple) {
@@ -283,14 +316,53 @@
}
nn::GeneralResult<nn::SharedMemory> createSharedMemoryFromHidlMemory(const hidl_memory& memory) {
- CHECK_LE(memory.size(), std::numeric_limits<uint32_t>::max());
+ CHECK_LE(memory.size(), std::numeric_limits<size_t>::max());
+ if (!memory.valid()) {
+ return NN_ERROR() << "Unable to convert invalid hidl_memory";
+ }
+
+ if (memory.name() == "ashmem") {
+ if (memory.handle()->numFds != 1) {
+ return NN_ERROR() << "Unable to convert invalid ashmem memory object with "
+ << memory.handle()->numFds << " numFds, but expected 1";
+ }
+ if (memory.handle()->numInts != 0) {
+ return NN_ERROR() << "Unable to convert invalid ashmem memory object with "
+ << memory.handle()->numInts << " numInts, but expected 0";
+ }
+ auto handle = nn::Memory::Ashmem{
+ .fd = NN_TRY(nn::dupFd(memory.handle()->data[0])),
+ .size = static_cast<size_t>(memory.size()),
+ };
+ return std::make_shared<const nn::Memory>(nn::Memory{.handle = std::move(handle)});
+ }
+
+ if (memory.name() == "mmap_fd") {
+ if (memory.handle()->numFds != 1) {
+ return NN_ERROR() << "Unable to convert invalid mmap_fd memory object with "
+ << memory.handle()->numFds << " numFds, but expected 1";
+ }
+ if (memory.handle()->numInts != 3) {
+ return NN_ERROR() << "Unable to convert invalid mmap_fd memory object with "
+ << memory.handle()->numInts << " numInts, but expected 3";
+ }
+
+ const int fd = memory.handle()->data[0];
+ const int prot = memory.handle()->data[1];
+ const int lower = memory.handle()->data[2];
+ const int higher = memory.handle()->data[3];
+ const size_t offset = nn::getOffsetFromInts(lower, higher);
+
+ return nn::createSharedMemoryFromFd(static_cast<size_t>(memory.size()), prot, fd, offset);
+ }
if (memory.name() != "hardware_buffer_blob") {
- return std::make_shared<const nn::Memory>(nn::Memory{
+ auto handle = nn::Memory::Unknown{
.handle = NN_TRY(sharedHandleFromNativeHandle(memory.handle())),
- .size = static_cast<uint32_t>(memory.size()),
+ .size = static_cast<size_t>(memory.size()),
.name = memory.name(),
- });
+ };
+ return std::make_shared<const nn::Memory>(nn::Memory{.handle = std::move(handle)});
}
const auto size = memory.size();
@@ -328,11 +400,7 @@
<< "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(),
- });
+ return nn::createSharedMemoryFromAHWB(hardwareBuffer, /*takeOwnership=*/true);
}
nn::GeneralResult<hidl_handle> hidlHandleFromSharedHandle(const nn::Handle& handle) {
diff --git a/neuralnetworks/utils/service/src/Service.cpp b/neuralnetworks/utils/service/src/Service.cpp
index c83bcc9..75ab1f9 100644
--- a/neuralnetworks/utils/service/src/Service.cpp
+++ b/neuralnetworks/utils/service/src/Service.cpp
@@ -16,6 +16,7 @@
#include "Service.h"
+#include <AndroidVersionUtil.h>
#include <aidl/android/hardware/neuralnetworks/IDevice.h>
#include <android-base/logging.h>
#include <android/binder_manager.h>
@@ -82,7 +83,7 @@
// Devices with SDK level lower than 31 (Android S) don't have any AIDL drivers available, so
// there is no need for a workaround supported on lower levels.
- if (__builtin_available(android __ANDROID_API_S__, *)) {
+ if (__builtin_available(android __NNAPI_AIDL_MIN_ANDROID_API__, *)) {
AServiceManager_forEachDeclaredInstance(aidl_hal::IDevice::descriptor,
static_cast<void*>(&names), callback);
}
diff --git a/radio/1.6/IRadioIndication.hal b/radio/1.6/IRadioIndication.hal
index 9788345..05a7585 100644
--- a/radio/1.6/IRadioIndication.hal
+++ b/radio/1.6/IRadioIndication.hal
@@ -107,7 +107,7 @@
/**
* Indicates physical channel configurations.
*
- * An empty configs list indicates that the radio is in idle mode.
+ * An empty configs list shall be returned when the radio is in idle mode (i.e. RRC idle).
*
* @param type Type of radio indication
* @param configs Vector of PhysicalChannelConfigs
diff --git a/radio/1.6/IRadioResponse.hal b/radio/1.6/IRadioResponse.hal
index f2c06b7..60b0edc 100644
--- a/radio/1.6/IRadioResponse.hal
+++ b/radio/1.6/IRadioResponse.hal
@@ -232,6 +232,7 @@
* RadioError:RADIO_NOT_AVAILABLE
* RadioError:INTERNAL_ERR
* RadioError:REQUEST_NOT_SUPPORTED
+ * RadioError:INVALID_STATE
*/
oneway setNrDualConnectivityStateResponse(RadioResponseInfo info);
diff --git a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
index a9c21ff..87320da 100644
--- a/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
+++ b/radio/1.6/vts/functional/radio_hidl_hal_api.cpp
@@ -378,6 +378,7 @@
CheckAnyOfErrors(radioRsp_v1_6->rspInfo.error,
{::android::hardware::radio::V1_6::RadioError::RADIO_NOT_AVAILABLE,
::android::hardware::radio::V1_6::RadioError::INTERNAL_ERR,
+ ::android::hardware::radio::V1_6::RadioError::INVALID_STATE,
::android::hardware::radio::V1_6::RadioError::NONE}));
}
}
diff --git a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
index f3c5477..c2e21b6 100644
--- a/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
+++ b/security/keymint/aidl/android/hardware/security/keymint/KeyCreationResult.aidl
@@ -60,29 +60,36 @@
* `attestationKey` parameter of `generateKey()`, `importKey()` or `importWrappedKey()`), and in
* the non-attestaion case, whether the key can self-sign.
*
- * 1. Attestation with factory key. If Tag::ATTESTATION_CHALLENGE is provided and the
- * `attestationKey` parameter on the generate/import call is null, the returned certificate
- * chain must contain an attestation certificate signed with a factory-provisioned
- * attestation key, and the full certificate chain for that factory-provisioned attestation
- * key.
+ * 1. Asymmetric key attestation with factory key. If Tag::ATTESTATION_CHALLENGE is provided
+ * and the `attestationKey` parameter on the generate/import call is null, the returned
+ * certificate chain must contain an attestation certificate signed with a factory-
+ * provisioned attestation key, and the full certificate chain for that factory-provisioned
+ * attestation key. Tag::ATTESTATION_APPLICATION_ID must also be provided when the
+ * ATTESTATION_CHALLENGE is provided, otherwise ATTESTATION_APPLICATION_ID_MISSING will be
+ * returned.
*
- * 2. Attestation with caller-provided key. If Tag::ATTESTATION_CHALLENGE is provided and the
- * `attestationKey` parameter on the generat/import call is non-null and contains the key
- * blob of a key with KeyPurpose::ATTEST_KEY, the returned certificate chain must contain
- * only an attestation certificate signed with the specified key. The caller must know the
- * certificate chain for the provided key.
+ * 2. Asymmetric key attestation with caller-provided key. If Tag::ATTESTATION_CHALLENGE is
+ * provided and the `attestationKey` parameter on the generat/import call is non-null and
+ * contains the key blob of a key with KeyPurpose::ATTEST_KEY, the returned certificate
+ * chain must contain only an attestation certificate signed with the specified key. The
+ * caller must know the certificate chain for the provided key. Tag::
+ * ATTESTATION_APPLICATION_ID must also be provided when the ATTESTATION_CHALLENGE is
+ * provided, otherwise ATTESTATION_APPLICATION_ID_MISSING will be returned.
*
- * 3. Non-attestation with signing key. If Tag::ATTESTATION_CHALLENGE is not provided and the
- * generated/imported key has KeyPurpose::SIGN, then the returned certificate chain must
- * contain only a single self-signed certificate with no attestation extension.
+ * 3. Asymmetric key non-attestation with signing key. If Tag::ATTESTATION_CHALLENGE is not
+ * provided and the generated/imported key has KeyPurpose::SIGN, then the returned
+ * certificate chain must contain only a single self-signed certificate with no attestation
+ * extension. Tag::ATTESTATION_APPLICATION_ID will be ignored if provided.
*
- * 4. Non-attestation with non-signing key. If TAG::ATTESTATION_CHALLENGE is not provided and
- * the generated/imported key does not have KeyPurpose::SIGN, then the returned certificate
- * chain must contain only a single certificate with an empty signature and no attestation
- * extension.
+ * 4. Asymmetric key non-attestation with non-signing key. If TAG::ATTESTATION_CHALLENGE is
+ * not provided and the generated/imported key does not have KeyPurpose::SIGN, then the
+ * returned certificate chain must contain only a single certificate with an empty signature
+ * and no attestation extension. Tag::ATTESTATION_APPLICATION_ID will be ignored if
+ * provided.
*
- * 5. Symmetric key. If the generated/imported key is symmetric, the certificate chain must be
- * empty.
+ * 5. Symmetric key. If the generated/imported key is symmetric, the certificate chain must
+ * return empty, any Tag::ATTESTATION_CHALLENGE or Tag::ATTESTATION_APPLICATION_ID inputs,
+ * if provided, are ignored.
*/
Certificate[] certificateChain;
}
diff --git a/security/keymint/aidl/vts/functional/Android.bp b/security/keymint/aidl/vts/functional/Android.bp
index c1affa6..6c7309e 100644
--- a/security/keymint/aidl/vts/functional/Android.bp
+++ b/security/keymint/aidl/vts/functional/Android.bp
@@ -43,6 +43,8 @@
"android.hardware.security.keymint-V1-ndk_platform",
"android.hardware.security.secureclock-V1-ndk_platform",
"libcppbor_external",
+ "libcppcose",
+ "libkeymint_remote_prov_support",
"libkeymint_vts_test_utils",
],
test_suites: [
@@ -73,6 +75,9 @@
"android.hardware.security.keymint-V1-ndk_platform",
"android.hardware.security.secureclock-V1-ndk_platform",
"libcppbor_external",
+ "libcppcose",
+ "libgmock_ndk",
+ "libkeymint_remote_prov_support",
],
}
diff --git a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
index ce6f67a..3da0484 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.cpp
@@ -22,8 +22,12 @@
#include <android-base/logging.h>
#include <android/binder_manager.h>
+#include <cppbor_parse.h>
+#include <cppcose/cppcose.h>
#include <cutils/properties.h>
+#include <gmock/gmock.h>
#include <openssl/mem.h>
+#include <remote_prov/remote_prov_utils.h>
#include <keymint_support/attestation_record.h>
#include <keymint_support/key_param_output.h>
@@ -32,6 +36,7 @@
namespace aidl::android::hardware::security::keymint {
+using namespace cppcose;
using namespace std::literals::chrono_literals;
using std::endl;
using std::optional;
@@ -39,6 +44,7 @@
using ::testing::AssertionFailure;
using ::testing::AssertionResult;
using ::testing::AssertionSuccess;
+using ::testing::MatchesRegex;
::std::ostream& operator<<(::std::ostream& os, const AuthorizationSet& set) {
if (set.size() == 0)
@@ -897,7 +903,7 @@
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>());
+ std::to_string(att_hw_enforced[i].value.get<KeyParameterValue::integer>());
// strptime seems to require delimiters, but the tag value will
// be YYYYMMDD
date.insert(6, "-");
@@ -1118,6 +1124,121 @@
return retval;
}
+namespace {
+
+void check_cose_key(const vector<uint8_t>& data, bool testMode) {
+ auto [parsedPayload, __, payloadParseErr] = cppbor::parse(data);
+ ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
+
+ // The following check assumes that canonical CBOR encoding is used for the COSE_Key.
+ if (testMode) {
+ EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
+ MatchesRegex("{\n"
+ " 1 : 2,\n" // kty: EC2
+ " 3 : -7,\n" // alg: ES256
+ " -1 : 1,\n" // EC id: P256
+ // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
+ // sequence of 32 hexadecimal bytes, enclosed in braces and
+ // separated by commas. In this case, some Ed25519 public key.
+ " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
+ " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
+ " -70000 : null,\n" // test marker
+ "}"));
+ } else {
+ EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
+ MatchesRegex("{\n"
+ " 1 : 2,\n" // kty: EC2
+ " 3 : -7,\n" // alg: ES256
+ " -1 : 1,\n" // EC id: P256
+ // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
+ // sequence of 32 hexadecimal bytes, enclosed in braces and
+ // separated by commas. In this case, some Ed25519 public key.
+ " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
+ " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
+ "}"));
+ }
+}
+
+} // namespace
+
+void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
+ vector<uint8_t>* payload_value) {
+ auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
+ ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
+
+ ASSERT_NE(coseMac0->asArray(), nullptr);
+ ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
+
+ auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
+ ASSERT_NE(protParms, nullptr);
+
+ // Header label:value of 'alg': HMAC-256
+ ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n 1 : 5,\n}");
+
+ auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
+ ASSERT_NE(unprotParms, nullptr);
+ ASSERT_EQ(unprotParms->size(), 0);
+
+ // The payload is a bstr holding an encoded COSE_Key
+ auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
+ ASSERT_NE(payload, nullptr);
+ check_cose_key(payload->value(), testMode);
+
+ auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
+ ASSERT_TRUE(coseMac0Tag);
+ auto extractedTag = coseMac0Tag->value();
+ EXPECT_EQ(extractedTag.size(), 32U);
+
+ // Compare with tag generated with kTestMacKey. Should only match in test mode
+ auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
+ payload->value());
+ ASSERT_TRUE(testTag) << "Tag calculation failed: " << testTag.message();
+
+ if (testMode) {
+ EXPECT_EQ(*testTag, extractedTag);
+ } else {
+ EXPECT_NE(*testTag, extractedTag);
+ }
+ if (payload_value != nullptr) {
+ *payload_value = payload->value();
+ }
+}
+
+void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey) {
+ // Extract x and y affine coordinates from the encoded Cose_Key.
+ auto [parsedPayload, __, payloadParseErr] = cppbor::parse(coseKeyData);
+ ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
+ auto coseKey = parsedPayload->asMap();
+ const std::unique_ptr<cppbor::Item>& xItem = coseKey->get(cppcose::CoseKey::PUBKEY_X);
+ ASSERT_NE(xItem->asBstr(), nullptr);
+ vector<uint8_t> x = xItem->asBstr()->value();
+ const std::unique_ptr<cppbor::Item>& yItem = coseKey->get(cppcose::CoseKey::PUBKEY_Y);
+ ASSERT_NE(yItem->asBstr(), nullptr);
+ vector<uint8_t> y = yItem->asBstr()->value();
+
+ // Concatenate: 0x04 (uncompressed form marker) | x | y
+ vector<uint8_t> pubKeyData{0x04};
+ pubKeyData.insert(pubKeyData.end(), x.begin(), x.end());
+ pubKeyData.insert(pubKeyData.end(), y.begin(), y.end());
+
+ EC_KEY_Ptr ecKey = EC_KEY_Ptr(EC_KEY_new());
+ ASSERT_NE(ecKey, nullptr);
+ EC_GROUP_Ptr group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
+ ASSERT_NE(group, nullptr);
+ ASSERT_EQ(EC_KEY_set_group(ecKey.get(), group.get()), 1);
+ EC_POINT_Ptr point = EC_POINT_Ptr(EC_POINT_new(group.get()));
+ ASSERT_NE(point, nullptr);
+ ASSERT_EQ(EC_POINT_oct2point(group.get(), point.get(), pubKeyData.data(), pubKeyData.size(),
+ nullptr),
+ 1);
+ ASSERT_EQ(EC_KEY_set_public_key(ecKey.get(), point.get()), 1);
+
+ EVP_PKEY_Ptr pubKey = EVP_PKEY_Ptr(EVP_PKEY_new());
+ ASSERT_NE(pubKey, nullptr);
+ EVP_PKEY_assign_EC_KEY(pubKey.get(), ecKey.release());
+ *signingKey = std::move(pubKey);
+}
+
} // 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 4d97ea9..da174ce 100644
--- a/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
+++ b/security/keymint/aidl/vts/functional/KeyMintAidlTestBase.h
@@ -25,6 +25,7 @@
#include <aidl/android/hardware/security/keymint/ErrorCode.h>
#include <aidl/android/hardware/security/keymint/IKeyMintDevice.h>
+#include <aidl/android/hardware/security/keymint/MacedPublicKey.h>
#include <keymint_support/authorization_set.h>
#include <keymint_support/openssl_utils.h>
@@ -277,6 +278,10 @@
string bin2hex(const vector<uint8_t>& data);
X509_Ptr parse_cert_blob(const vector<uint8_t>& blob);
vector<uint8_t> make_name_from_str(const string& name);
+void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
+ vector<uint8_t>* payload_value);
+void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey);
+
AuthorizationSet HwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
AuthorizationSet SwEnforcedAuthorizations(const vector<KeyCharacteristics>& key_characteristics);
::testing::AssertionResult ChainSignaturesAreValid(const vector<Certificate>& chain);
diff --git a/security/keymint/aidl/vts/functional/KeyMintTest.cpp b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
index 7ecfa37..2d28845 100644
--- a/security/keymint/aidl/vts/functional/KeyMintTest.cpp
+++ b/security/keymint/aidl/vts/functional/KeyMintTest.cpp
@@ -27,6 +27,9 @@
#include <cutils/properties.h>
+#include <android/binder_manager.h>
+
+#include <aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.h>
#include <aidl/android/hardware/security/keymint/KeyFormat.h>
#include <keymint_support/key_param_output.h>
@@ -134,6 +137,54 @@
"d5f33645e8ed8b4a1cb3cc4a1d67987399f2a09f5b3fb68c88d5e5d90ac3"
"3492d6");
+/*
+ * DER-encoded PKCS#8 format RSA key. Generated using:
+ *
+ * openssl genrsa 2048 | openssl pkcs8 -topk8 -nocrypt -outform der | hexdump -e '30/1 "%02X" "\n"'
+ */
+string rsa_2048_key =
+ hex2str("308204BD020100300D06092A864886F70D0101010500048204A7308204A3"
+ "0201000282010100BEBC342B56D443B1299F9A6A7056E80A897E318476A5"
+ "A18029E63B2ED739A61791D339F58DC763D9D14911F2EDEC383DEE11F631"
+ "9B44510E7A3ECD9B79B97382E49500ACF8117DC89CAF0E621F77756554A2"
+ "FD4664BFE7AB8B59AB48340DBFA27B93B5A81F6ECDEB02D0759307128DF3"
+ "E3BAD4055C8B840216DFAA5700670E6C5126F0962FCB70FF308F25049164"
+ "CCF76CC2DA66A7DD9A81A714C2809D69186133D29D84568E892B6FFBF319"
+ "9BDB14383EE224407F190358F111A949552ABA6714227D1BD7F6B20DD0CB"
+ "88F9467B719339F33BFF35B3870B3F62204E4286B0948EA348B524544B5F"
+ "9838F29EE643B079EEF8A713B220D7806924CDF7295070C5020301000102"
+ "82010069F377F35F2F584EF075353CCD1CA99738DB3DBC7C7FF35F9366CE"
+ "176DFD1B135AB10030344ABF5FBECF1D4659FDEF1C0FC430834BE1BE3911"
+ "951377BB3D563A2EA9CA8F4AD9C48A8CE6FD516A735C662686C7B4B3C09A"
+ "7B8354133E6F93F790D59EAEB92E84C9A4339302CCE28FDF04CCCAFA7DE3"
+ "F3A827D4F6F7D38E68B0EC6AB706645BF074A4E4090D06FB163124365FD5"
+ "EE7A20D350E9958CC30D91326E1B292E9EF5DB408EC42DAF737D20149704"
+ "D0A678A0FB5B5446863B099228A352D604BA8091A164D01D5AB05397C71E"
+ "AD20BE2A08FC528FE442817809C787FEE4AB97F97B9130D022153EDC6EB6"
+ "CBE7B0F8E3473F2E901209B5DB10F93604DB0102818100E83C0998214941"
+ "EA4F9293F1B77E2E99E6CF305FAF358238E126124FEAF2EB9724B2EA7B78"
+ "E6032343821A80E55D1D88FB12D220C3F41A56142FEC85796D1917F1E8C7"
+ "74F142B67D3D6E7B7E6B4383E94DB5929089DBB346D5BDAB40CC2D96EE04"
+ "09475E175C63BF78CFD744136740838127EA723FF3FE7FA368C1311B4A4E"
+ "0502818100D240FCC0F5D7715CDE21CB2DC86EA146132EA3B06F61FF2AF5"
+ "4BF38473F59DADCCE32B5F4CC32DD0BA6F509347B4B5B1B58C39F95E4798"
+ "CCBB43E83D0119ACF532F359CA743C85199F0286610E200997D731291717"
+ "9AC9B67558773212EC961E8BCE7A3CC809BC5486A96E4B0E6AF394D94E06"
+ "6A0900B7B70E82A44FB30053C102818100AD15DA1CBD6A492B66851BA8C3"
+ "16D38AB700E2CFDDD926A658003513C54BAA152B30021D667D20078F500F"
+ "8AD3E7F3945D74A891ED1A28EAD0FEEAEC8C14A8E834CF46A13D1378C99D"
+ "18940823CFDD27EC5810D59339E0C34198AC638E09C87CBB1B634A9864AE"
+ "9F4D5EB2D53514F67B4CAEC048C8AB849A02E397618F3271350281801FA2"
+ "C1A5331880A92D8F3E281C617108BF38244F16E352E69ED417C7153F9EC3"
+ "18F211839C643DCF8B4DD67CE2AC312E95178D5D952F06B1BF779F491692"
+ "4B70F582A23F11304E02A5E7565AE22A35E74FECC8B6FDC93F92A1A37703"
+ "E4CF0E63783BD02EB716A7ECBBFA606B10B74D01579522E7EF84D91FC522"
+ "292108D902C1028180796FE3825F9DCC85DF22D58690065D93898ACD65C0"
+ "87BEA8DA3A63BF4549B795E2CD0E3BE08CDEBD9FCF1720D9CDC5070D74F4"
+ "0DED8E1102C52152A31B6165F83A6722AECFCC35A493D7634664B888A08D"
+ "3EB034F12EA28BFEE346E205D334827F778B16ED40872BD29FCB36536B6E"
+ "93FFB06778696B4A9D81BB0A9423E63DE5");
+
string ec_256_key =
hex2str("308187020100301306072a8648ce3d020106082a8648ce3d030107046d30"
"6b0201010420737c2ecd7b8d1940bf2930aa9b4ed3ff941eed09366bc032"
@@ -209,6 +260,32 @@
string to_string() const { return string(reinterpret_cast<const char*>(data()), size()); }
};
+string device_suffix(const string& name) {
+ size_t pos = name.find('/');
+ if (pos == string::npos) {
+ return name;
+ }
+ return name.substr(pos + 1);
+}
+
+bool matching_rp_instance(const string& km_name,
+ std::shared_ptr<IRemotelyProvisionedComponent>* rp) {
+ string km_suffix = device_suffix(km_name);
+
+ vector<string> rp_names =
+ ::android::getAidlHalInstanceNames(IRemotelyProvisionedComponent::descriptor);
+ for (const string& rp_name : rp_names) {
+ // If the suffix of the RemotelyProvisionedComponent instance equals the suffix of the
+ // KeyMint instance, assume they match.
+ if (device_suffix(rp_name) == km_suffix && AServiceManager_isDeclared(rp_name.c_str())) {
+ ::ndk::SpAIBinder binder(AServiceManager_waitForService(rp_name.c_str()));
+ *rp = IRemotelyProvisionedComponent::fromBinder(binder);
+ return true;
+ }
+ }
+ return false;
+}
+
} // namespace
class NewKeyGenerationTest : public KeyMintAidlTestBase {
@@ -322,6 +399,77 @@
}
/*
+ * NewKeyGenerationTest.RsaWithRpkAttestation
+ *
+ * Verifies that keymint can generate all required RSA key sizes, using an attestation key
+ * that has been generated using an associate IRemotelyProvisionedComponent.
+ */
+TEST_P(NewKeyGenerationTest, RsaWithRpkAttestation) {
+ // There should be an IRemotelyProvisionedComponent instance associated with the KeyMint
+ // instance.
+ std::shared_ptr<IRemotelyProvisionedComponent> rp;
+ ASSERT_TRUE(matching_rp_instance(GetParam(), &rp))
+ << "No IRemotelyProvisionedComponent found that matches KeyMint device " << GetParam();
+
+ // Generate a P-256 keypair to use as an attestation key.
+ MacedPublicKey macedPubKey;
+ std::vector<uint8_t> privateKeyBlob;
+ auto status =
+ rp->generateEcdsaP256KeyPair(/* testMode= */ false, &macedPubKey, &privateKeyBlob);
+ ASSERT_TRUE(status.isOk());
+ vector<uint8_t> coseKeyData;
+ check_maced_pubkey(macedPubKey, /* testMode= */ false, &coseKeyData);
+
+ AttestationKey attestation_key;
+ attestation_key.keyBlob = std::move(privateKeyBlob);
+ attestation_key.issuerSubjectName = make_name_from_str("Android Keystore Key");
+
+ for (auto key_size : ValidKeySizes(Algorithm::RSA)) {
+ auto challenge = "hello";
+ auto app_id = "foo";
+
+ vector<uint8_t> key_blob;
+ vector<KeyCharacteristics> key_characteristics;
+ ASSERT_EQ(ErrorCode::OK,
+ GenerateKey(AuthorizationSetBuilder()
+ .RsaSigningKey(key_size, 65537)
+ .Digest(Digest::NONE)
+ .Padding(PaddingMode::NONE)
+ .AttestationChallenge(challenge)
+ .AttestationApplicationId(app_id)
+ .Authorization(TAG_NO_AUTH_REQUIRED)
+ .SetDefaultValidity(),
+ attestation_key, &key_blob, &key_characteristics, &cert_chain_));
+
+ ASSERT_GT(key_blob.size(), 0U);
+ CheckBaseParams(key_characteristics);
+
+ AuthorizationSet crypto_params = SecLevelAuthorizations(key_characteristics);
+
+ EXPECT_TRUE(crypto_params.Contains(TAG_ALGORITHM, Algorithm::RSA));
+ EXPECT_TRUE(crypto_params.Contains(TAG_KEY_SIZE, key_size))
+ << "Key size " << key_size << "missing";
+ EXPECT_TRUE(crypto_params.Contains(TAG_RSA_PUBLIC_EXPONENT, 65537U));
+
+ // Attestation by itself is not valid (last entry is not self-signed).
+ EXPECT_FALSE(ChainSignaturesAreValid(cert_chain_));
+
+ // The signature over the attested key should correspond to the P256 public key.
+ X509_Ptr key_cert(parse_cert_blob(cert_chain_[0].encodedCertificate));
+ ASSERT_TRUE(key_cert.get());
+ EVP_PKEY_Ptr signing_pubkey;
+ p256_pub_key(coseKeyData, &signing_pubkey);
+ ASSERT_TRUE(signing_pubkey.get());
+
+ ASSERT_TRUE(X509_verify(key_cert.get(), signing_pubkey.get()))
+ << "Verification of attested certificate failed "
+ << "OpenSSL error string: " << ERR_error_string(ERR_get_error(), NULL);
+
+ CheckedDeleteKey(&key_blob);
+ }
+}
+
+/*
* NewKeyGenerationTest.LimitedUsageRsa
*
* Verifies that KeyMint can generate all required RSA key sizes with limited usage, and that the
@@ -1711,16 +1859,27 @@
* Verifies that importing and using an RSA key pair works correctly.
*/
TEST_P(ImportKeyTest, RsaSuccess) {
+ uint32_t key_size;
+ string key;
+
+ if (SecLevel() == SecurityLevel::STRONGBOX) {
+ key_size = 2048;
+ key = rsa_2048_key;
+ } else {
+ key_size = 1024;
+ key = rsa_key;
+ }
+
ASSERT_EQ(ErrorCode::OK, ImportKey(AuthorizationSetBuilder()
.Authorization(TAG_NO_AUTH_REQUIRED)
- .RsaSigningKey(1024, 65537)
+ .RsaSigningKey(key_size, 65537)
.Digest(Digest::SHA_2_256)
.Padding(PaddingMode::RSA_PSS)
.SetDefaultValidity(),
- KeyFormat::PKCS8, rsa_key));
+ KeyFormat::PKCS8, key));
CheckCryptoParam(TAG_ALGORITHM, Algorithm::RSA);
- CheckCryptoParam(TAG_KEY_SIZE, 1024U);
+ CheckCryptoParam(TAG_KEY_SIZE, key_size);
CheckCryptoParam(TAG_RSA_PUBLIC_EXPONENT, 65537U);
CheckCryptoParam(TAG_DIGEST, Digest::SHA_2_256);
CheckCryptoParam(TAG_PADDING, PaddingMode::RSA_PSS);
diff --git a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
index 57bc27a..9e52b20 100644
--- a/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
+++ b/security/keymint/aidl/vts/functional/VtsRemotelyProvisionedComponentTests.cpp
@@ -55,117 +55,6 @@
return bytevec(p, p + strlen(s));
}
-void p256_pub_key(const vector<uint8_t>& coseKeyData, EVP_PKEY_Ptr* signingKey) {
- // Extract x and y affine coordinates from the encoded Cose_Key.
- auto [parsedPayload, __, payloadParseErr] = cppbor::parse(coseKeyData);
- ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
- auto coseKey = parsedPayload->asMap();
- const std::unique_ptr<cppbor::Item>& xItem = coseKey->get(cppcose::CoseKey::PUBKEY_X);
- ASSERT_NE(xItem->asBstr(), nullptr);
- vector<uint8_t> x = xItem->asBstr()->value();
- const std::unique_ptr<cppbor::Item>& yItem = coseKey->get(cppcose::CoseKey::PUBKEY_Y);
- ASSERT_NE(yItem->asBstr(), nullptr);
- vector<uint8_t> y = yItem->asBstr()->value();
-
- // Concatenate: 0x04 (uncompressed form marker) | x | y
- vector<uint8_t> pubKeyData{0x04};
- pubKeyData.insert(pubKeyData.end(), x.begin(), x.end());
- pubKeyData.insert(pubKeyData.end(), y.begin(), y.end());
-
- EC_KEY_Ptr ecKey = EC_KEY_Ptr(EC_KEY_new());
- ASSERT_NE(ecKey, nullptr);
- EC_GROUP_Ptr group = EC_GROUP_Ptr(EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1));
- ASSERT_NE(group, nullptr);
- ASSERT_EQ(EC_KEY_set_group(ecKey.get(), group.get()), 1);
- EC_POINT_Ptr point = EC_POINT_Ptr(EC_POINT_new(group.get()));
- ASSERT_NE(point, nullptr);
- ASSERT_EQ(EC_POINT_oct2point(group.get(), point.get(), pubKeyData.data(), pubKeyData.size(),
- nullptr),
- 1);
- ASSERT_EQ(EC_KEY_set_public_key(ecKey.get(), point.get()), 1);
-
- EVP_PKEY_Ptr pubKey = EVP_PKEY_Ptr(EVP_PKEY_new());
- ASSERT_NE(pubKey, nullptr);
- EVP_PKEY_assign_EC_KEY(pubKey.get(), ecKey.release());
- *signingKey = std::move(pubKey);
-}
-
-void check_cose_key(const vector<uint8_t>& data, bool testMode) {
- auto [parsedPayload, __, payloadParseErr] = cppbor::parse(data);
- ASSERT_TRUE(parsedPayload) << "Key parse failed: " << payloadParseErr;
-
- // The following check assumes that canonical CBOR encoding is used for the COSE_Key.
- if (testMode) {
- EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
- MatchesRegex("{\n"
- " 1 : 2,\n" // kty: EC2
- " 3 : -7,\n" // alg: ES256
- " -1 : 1,\n" // EC id: P256
- // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
- // sequence of 32 hexadecimal bytes, enclosed in braces and
- // separated by commas. In this case, some Ed25519 public key.
- " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
- " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
- " -70000 : null,\n" // test marker
- "}"));
- } else {
- EXPECT_THAT(cppbor::prettyPrint(parsedPayload.get()),
- MatchesRegex("{\n"
- " 1 : 2,\n" // kty: EC2
- " 3 : -7,\n" // alg: ES256
- " -1 : 1,\n" // EC id: P256
- // The regex {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}} matches a
- // sequence of 32 hexadecimal bytes, enclosed in braces and
- // separated by commas. In this case, some Ed25519 public key.
- " -2 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_x: data
- " -3 : {(0x[0-9a-f]{2}, ){31}0x[0-9a-f]{2}},\n" // pub_y: data
- "}"));
- }
-}
-
-void check_maced_pubkey(const MacedPublicKey& macedPubKey, bool testMode,
- vector<uint8_t>* payload_value) {
- auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
- ASSERT_TRUE(coseMac0) << "COSE Mac0 parse failed " << mac0ParseErr;
-
- ASSERT_NE(coseMac0->asArray(), nullptr);
- ASSERT_EQ(coseMac0->asArray()->size(), kCoseMac0EntryCount);
-
- auto protParms = coseMac0->asArray()->get(kCoseMac0ProtectedParams)->asBstr();
- ASSERT_NE(protParms, nullptr);
-
- // Header label:value of 'alg': HMAC-256
- ASSERT_EQ(cppbor::prettyPrint(protParms->value()), "{\n 1 : 5,\n}");
-
- auto unprotParms = coseMac0->asArray()->get(kCoseMac0UnprotectedParams)->asMap();
- ASSERT_NE(unprotParms, nullptr);
- ASSERT_EQ(unprotParms->size(), 0);
-
- // The payload is a bstr holding an encoded COSE_Key
- auto payload = coseMac0->asArray()->get(kCoseMac0Payload)->asBstr();
- ASSERT_NE(payload, nullptr);
- check_cose_key(payload->value(), testMode);
-
- auto coseMac0Tag = coseMac0->asArray()->get(kCoseMac0Tag)->asBstr();
- ASSERT_TRUE(coseMac0Tag);
- auto extractedTag = coseMac0Tag->value();
- EXPECT_EQ(extractedTag.size(), 32U);
-
- // Compare with tag generated with kTestMacKey. Should only match in test mode
- auto testTag = cppcose::generateCoseMac0Mac(remote_prov::kTestMacKey, {} /* external_aad */,
- payload->value());
- ASSERT_TRUE(testTag) << "Tag calculation failed: " << testTag.message();
-
- if (testMode) {
- EXPECT_EQ(*testTag, extractedTag);
- } else {
- EXPECT_NE(*testTag, extractedTag);
- }
- if (payload_value != nullptr) {
- *payload_value = payload->value();
- }
-}
-
ErrMsgOr<MacedPublicKey> corrupt_maced_key(const MacedPublicKey& macedPubKey) {
auto [coseMac0, _, mac0ParseErr] = cppbor::parse(macedPubKey.macedKey);
if (!coseMac0 || coseMac0->asArray()->size() != kCoseMac0EntryCount) {
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/IWeaver.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/IWeaver.aidl
index 29bd9a9..61627d9 100644
--- a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/IWeaver.aidl
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/IWeaver.aidl
@@ -12,7 +12,8 @@
* 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. //
///////////////////////////////////////////////////////////////////////////////
@@ -37,6 +38,6 @@
android.hardware.weaver.WeaverReadResponse read(in int slotId, in byte[] key);
void write(in int slotId, in byte[] key, in byte[] value);
const int STATUS_FAILED = 1;
- const int INCORRECT_KEY = 2;
- const int THROTTLE = 3;
+ const int STATUS_INCORRECT_KEY = 2;
+ const int STATUS_THROTTLE = 3;
}
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverConfig.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverConfig.aidl
index 239cdac..7491f32 100644
--- a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverConfig.aidl
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverConfig.aidl
@@ -12,7 +12,8 @@
* 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. //
///////////////////////////////////////////////////////////////////////////////
@@ -33,7 +34,7 @@
package android.hardware.weaver;
@VintfStability
parcelable WeaverConfig {
- long slots;
- long keySize;
- long valueSize;
+ int slots;
+ int keySize;
+ int valueSize;
}
diff --git a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
index 7e5db59..47ee4c8 100644
--- a/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
+++ b/weaver/aidl/aidl_api/android.hardware.weaver/current/android/hardware/weaver/WeaverReadResponse.aidl
@@ -12,7 +12,8 @@
* 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. //
///////////////////////////////////////////////////////////////////////////////
diff --git a/weaver/aidl/android/hardware/weaver/IWeaver.aidl b/weaver/aidl/android/hardware/weaver/IWeaver.aidl
index ebbfabe..f51034a 100644
--- a/weaver/aidl/android/hardware/weaver/IWeaver.aidl
+++ b/weaver/aidl/android/hardware/weaver/IWeaver.aidl
@@ -46,8 +46,8 @@
* Read binder calls may return a ServiceSpecificException with the following error codes.
*/
const int STATUS_FAILED = 1;
- const int INCORRECT_KEY = 2;
- const int THROTTLE = 3;
+ const int STATUS_INCORRECT_KEY = 2;
+ const int STATUS_THROTTLE = 3;
/**
* Attempts to retrieve the value stored in the identified slot.
diff --git a/weaver/aidl/android/hardware/weaver/WeaverConfig.aidl b/weaver/aidl/android/hardware/weaver/WeaverConfig.aidl
index 75d961e..a156a7b 100644
--- a/weaver/aidl/android/hardware/weaver/WeaverConfig.aidl
+++ b/weaver/aidl/android/hardware/weaver/WeaverConfig.aidl
@@ -21,14 +21,14 @@
/**
* The number of slots available.
*/
- long slots;
+ int slots;
/**
* The number of bytes used for a key.
*/
- long keySize;
+ int keySize;
/**
* The number of bytes used for a value.
*/
- long valueSize;
+ int valueSize;
}
diff --git a/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp b/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
index 7d8daa2..878c762 100644
--- a/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
+++ b/weaver/aidl/vts/VtsHalWeaverTargetTest.cpp
@@ -156,7 +156,7 @@
ASSERT_FALSE(readRet.isOk());
ASSERT_EQ(EX_SERVICE_SPECIFIC, readRet.getExceptionCode());
- ASSERT_EQ(IWeaver::INCORRECT_KEY, readRet.getServiceSpecificError());
+ ASSERT_EQ(IWeaver::STATUS_INCORRECT_KEY, readRet.getServiceSpecificError());
EXPECT_TRUE(readValue.empty());
}