Snap for 8712302 from f828bd264ce333a35dad7a9e0a2eb1558ab88fd8 to tm-frc-networking-release Change-Id: I369ce0f6644d447f27c7b3007d93b8890c681c7d
diff --git a/security/keymint/RKP_README.md b/security/keymint/RKP_README.md new file mode 100644 index 0000000..89a2598 --- /dev/null +++ b/security/keymint/RKP_README.md
@@ -0,0 +1,374 @@ +# Remote Provisioning HAL + +## Objective + +Design a HAL to support over-the-air provisioning of certificates for asymmetric +keys. The HAL must interact effectively with Keystore (and other daemons) and +protect device privacy and security. + +Note that this API is designed for KeyMint, but with the intention that it +should be usable for other HALs that require certificate provisioning. +Throughout this document we'll refer to the Keystore and KeyMint (formerly +called Keymaster) components, but only for concreteness and convenience; those +labels could be replaced with the names of any system and secure area +components, respectively, that need certificates provisioned. + +## Key design decisions + +### General approach + +To more securely and reliably get keys and certificates to Android devices, we +need to create a system where no party outside of the device's secure components +is responsible for managing private keys. The strategy we've chosen is to +deliver certificates over the air, using an asymmetric key pair created +on-device in the factory as a root of trust to create an authenticated, secure +channel. In this document we refer to this device-unique asymmetric key pair as +Device Key (DK), its public half DK\_pub, its private half DK\_priv and a Device +Key Certificate containing DK\_pub is denoted DKC. + +In order for the provisioning service to use DK (or a key authenticated by DK), +it must know whether a given DK\_pub is known and trusted. To prove trust, we +ask device OEMs to use one of two mechanisms: + +1. (Preferred, recommended) The device OEM extracts DK\_pub from each device it + manufactures and uploads the public keys to a backend server. + +1. The device OEM signs the DK\_pub to produce DKC and stores it on the device. + This has the advantage that they don't need to upload a DK\_pub for every + device immediately, but the disadvantage that they have to manage their + private signing keys, which means they have to have HSMs, configure and + secure them correctly, etc. Some backend providers may also require that the + OEM passes a factory security audit, and additionally promises to upload the + keys eventually as well. + +Note that in the full elaboration of this plan, DK\_pub is not the key used to +establish a secure channel. Instead, DK\_pub is just the first public key in a +chain of public keys which ends with the KeyMint public key, KM\_pub. All keys +in the chain are device-unique and are joined in a certificate chain called the +_Boot Certificate Chain_ (BCC), because in phases 2 and 3 of the remote +provisioning project it is a chain of certificates corresponding to boot phases. +We speak of the BCC even for phase 1, though in phase 1 it contains only a +single self-signed DKC. This is described in more depth in the Phases section +below. + +The BCC is authenticated by DK\_pub. To authenticate DK\_pub, we may have +additional DKCs, from the SoC vendor, the device OEM, or both. Those are not +part of the BCC but included as optional fields in the certificate request +structure. + +The format of the the DK and BCC is specified within [Open Profile for DICE] +(https://pigweed.googlesource.com/open-dice/+/HEAD/docs/specification.md). To +map phrases within this document to their equivalent terminology in the DICE +specification, read the terms as follows: the DK corresponds to the UDS-derived +key pair, DKC corresponds to the UDS certificate, and the BCC entries between +DK\_pub and KM\_pub correspond to a chain of CDI certificates. + +Note: In addition to allowing 32 byte hash values for fields in the BCC payload, +this spec additionally constrains some of the choices allowed in open-DICE. +Specifically, these include which entries are required and which are optional in +the BCC payload, and which algorithms are acceptable for use. + +### Phases + +RKP will be deployed in three phases, in terms of managing the root of trust +binding between the device and the backend. To briefly describe them: + +* Phase 1: In phase 1 there is only one entry in the BCC; DK_pub and KM_pub are + the same key and the certificate is self-signed. +* Phase 2: This is identical to phase 1, except it leverages the hardware root + of trust process described by DICE. Instead of trust being rooted in the TEE, + it is now rooted in the ROM by key material blown into fuses which are only + accessible to the ROM code. +* Phase 3: This is identical to Phase 2, except the SoC vendor also does the + public key extraction or certification in their facilities, along with the OEM + doing it in the factory. This tightens up the "supply chain" and aims to make + key upload management more secure. + +### Privacy considerations + +Because DK and the DKCs are unique, immutable, unspoofable hardware-bound +identifiers for the device, we must limit access to them to the absolute minimum +possible. We do this in two ways: + +1. We require KeyMint (which knows the BCC and either knows or at least has the +ability to use KM\_priv) to refuse to ever divulge the BCC or additional +signatures in plaintext. Instead, KeyMint requires the caller to provide an +_Endpoint Encryption Key_ (EEK), with which it will encrypt the data before +returning it. When provisioning production keys, the EEK must be signed by an +approved authority whose public key is embedded in KeyMint. When certifying test +keys, KeyMint will accept any EEK without checking the signature, but will +encrypt and return a test BCC, rather than the real one. The result is that +only an entity in possession of an Trusted EEK (TEEK) private key can discover +the plaintext of the production BCC. +1. Having thus limited access to the public keys to the trusted party only, we +need to prevent the entity from abusing this unique device identifier. The +approach and mechanisms for doing that are beyond the scope of this document +(they must be addressed in the server design), but generally involve taking care +to ensure that we do not create any links between user IDs, IP addresses or +issued certificates and the device pubkey. + +Although the details of the mechanisms for preventing the entity from abusing +the BCC are, as stated, beyond the scope of this document, there is a subtle +design decision here made specifically to enable abuse prevention. Specifically +the `CertificateRequest` message sent to the server is (in +[CDDL](https://tools.ietf.org/html/rfc8610)): + +``` +cddl +CertificateRequest = [ + DeviceInfo, + challenge : bstr, + ProtectedData, + MacedKeysToSign +] +``` + +The public keys to be attested by the server are in `MacedKeysToSign`, which is +a COSE\_Mac0 structure, MACed with a key that is found in `ProtectedData`. The +MAC key is signed by DK\_pub. + +This structure allows the backend component that has access to EEK\_priv to +decrypt `ProtectedData`, validate that the request is from an authorized device, +check that the request is fresh and verify and extract the MAC key. That backend +component never sees any data related to the keys to be signed, but can provide +the MAC key to another backend component that can verify `MacedKeysToSign` and +proceed to generate the certificates. + +In this way, we can partition the provisioning server into one component that +knows the device identity, as represented by DK\_pub, but never sees the keys to +be certified or certificates generated, and another component that sees the keys +to be certified and certificates generated but does not know the device +identity. + +### Key and cryptographic message formatting + +For simplicity of generation and parsing, compactness of wire representation, +and flexibility and standardization, we've settled on using the CBOR Object +Signing and Encryption (COSE) standard, defined in [RFC +8152](https://tools.ietf.org/html/rfc8152). COSE provides compact and reasonably +simple, yet easily-extensible, wire formats for: + +* Keys, +* MACed messages, +* Signed messages, and +* Encrypted messages + +COSE enables easy layering of these message formats, such as using a COSE\_Sign +structure to contain a COSE\_Key with a public key in it. We call this a +"certificate". + +Due to the complexity of the standard, we'll spell out the COSE structures +completely in this document and in the HAL and other documentation, so that +although implementors will need to understand CBOR and the CBOR Data Definition +Language ([CDDL, defined in RFC 8610](https://tools.ietf.org/html/rfc8610)), +they shouldn't need to understand COSE. + +Note, however, that the certificate chains returned from the provisioning server +are standard X.509 certificates. + +### Algorithm choices + +This document uses: + +* ECDSA P-256 for attestation signing keys; +* Remote provisioning protocol signing keys: + * Ed25519 / P-256 +* ECDH keys: + * X25519 / P-256 +* AES-GCM for all encryption; +* SHA-256 for all message digesting; +* HMAC-SHA-256 for all MACing; and +* HKDF-SHA-256 for all key derivation. + +We believe that Curve25519 offers the best tradeoff in terms of security, +efficiency and global trustworthiness, and that it is now sufficiently +widely-used and widely-implemented to make it a practical choice. + +However, since Secure Elements (SE) do not currently offer support for curve +25519, we are allowing implementations to instead make use of EC P-256 for +signing and ECDH. To put it simply, the device unique key pair will be a P-256 +key pair for ECDSA instead of Ed25519, and the ProtectedData COSE\_Encrypt +message will have its payload encrypted with P-256 ECDH key exchange instead of +X25519. + +The CDDL in the rest of the document will use the '/' operator to show areas +where either curve 25519 or P-256 may be used. Since there is no easy way to +bind choices across different CDDL groups, it is important that the implementor +stays consistent in which type is chosen. E.g. taking ES256 as the choice for +algorithm implies the implementor should also choose the P256 public key group +further down in the COSE structure. + +### Testability + +It's critical that the remote provisioning implementation be testable, to +minimize the probability that broken devices are sold to end users. To support +testing, the remote provisioning HAL methods take a `testMode` argument. Keys +created in test mode are tagged to indicate this. The provisioning server will +check for the test mode tag and issue test certificates that do not chain back +to a trusted public key. In test mode, any EEK will be accepted, enabling +testing tools to use EEKs for which they have the private key so they can +validate the content of certificate requests. The BCC included in the +`CertificateRequest` must contain freshly-generated keys, not the real BCC keys. + +Keystore (or similar) will need to be able to handle both testMode keys and +production keys and keep them distinct, generating test certificate requests +when asked with a test EEK and production certificate requests when asked with a +production EEK. Likewise, the interface used to instruct Keystore to create keys +will need to be able to specify whether test or production keys are desired. + +## Design + +### Certificate provisioning flow + +TODO(jbires): Replace this with a `.png` containing a sequence diagram. The +provisioning flow looks something like this: + +Provisioner -> Keystore: Prepare N keys +Keystore -> KeyMint: generateKeyPair +KeyMint -> KeyMint: Generate key pair +KeyMint --> Keystore: key\_blob,pubkey +Keystore -> Keystore: Store key\_blob,pubkey +Provisioner -> Server: Get TEEK +Server --> Provisioner: TEEK +Provisioner -> Keystore: genCertReq(N, TEEK) +Keystore -> KeyMint: genCertReq(pubkeys, TEEK) +KeyMint -> KeyMint: Sign pubkeys & encrypt BCC +KeyMint --> Keystore: signature, encrypted BCC +Keystore -> Keystore: Construct cert\_request +Keystore --> Provisioner: cert\_request +Provisioner --> Server: cert\_request +Server -> Server: Validate cert\_request +Server -> Server: Generate certificates +Server --> Provisioner: certificates +Provisioner -> Keystore: certificates +Keystore -> Keystore: Store certificates + +The actors in the above diagram are: + +* **Server** is the backend certificate provisioning server. It has access to + the uploaded device public keys and is responsible for providing encryption + keys, decrypting and validating requests, and generating certificates in + response to requests. +* **Provisioner** is an application that is responsible for communicating with + the server and all of the system components that require key certificates + from the server. It also implements the policy that defines how many key + pairs each client should keep in their pool. +* **Keystore** is the [Android keystore + daemon](https://developer.android.com/training/articles/keystore) (or, more + generally, whatever system component manages communications with a + particular secure aread component). +* **KeyMint** is the secure area component that manages cryptographic keys and + performs attestations (or perhaps some other secure area component). + +### `BCC` + +The _Boot Certificate Chain_ (BCC) is the chain of certificates that contains +DK\_pub as well as other often device-unique certificates. The BCC is +represented as a COSE\_Key containing DK\_pub followed by an array of +COSE\_Sign1 "certificates" containing public keys and optional additional +information, ordered from root to leaf, with each certificate signing the next. +The first certificate in the array is signed by DK\_pub, the last certificate +has the KeyMint (or whatever) signing key's public key, KM\_pub. In phase 1 +there is only one entry; DK\_pub and KM\_pub are the same key and the +certificate is self-signed. + +Each COSE\_Sign1 certificate is a CBOR Web Token (CWT) as described in [RFC +8392](https://tools.ietf.org/html/rfc8392) with additional fields as described +in the Open Profile for DICE. Of these additional fields, only the +_subjectPublicKey_ and _keyUsage_ fields are expected to be present for the +KM\_pub entry (that is, the last entry) in a BCC, but all fields required by the +Open Profile for DICE are expected for other entries (each of which corresponds +to a particular firmware component or boot stage). The CWT fields _iss_ and +_sub_ identify the issuer and subject of the certificate and are consistent +along the BCC entries; the issuer of a given entry matches the subject of the +previous entry. + +The BCC is designed to be constructed using the Open Profile for DICE. In this +case the DK key pair is derived from the UDS as described by that profile and +all BCC entries before the leaf are CBOR CDI certificates chained from DK\_pub. +The KM key pair is not part of the derived DICE chain. It is generated (not +derived) by the KeyMint module, certified by the last key in the DICE chain, and +added as the leaf BCC entry. The key usage field in this leaf certificate must +indicate the key is not used to sign certificates. If a UDS certificate is +available on the device it should appear in the certificate request as the leaf +of a DKCertChain in AdditionalDKSignatures (see +[CertificateRequest](#certificaterequest)). + +The Open Profile for DICE allows for an arbitrary configuration descriptor. For +BCC entries, this configuration descriptor is a CBOR map with the following +optional fields. If no fields are relevant, an empty map should be encoded. +Additional implementation-specific fields may be added using key values not in +the range \[-70000, -70999\] (these are reserved for future additions here). + +``` +| Name | Key | Value type | Meaning | +| ----------------- | ------ | ---------- | ----------------------------------| +| Component name | -70002 | tstr | Name of firmware component / boot | +: : : : stage : +| Component version | -70003 | int | Version of firmware component / | +: : : : boot stage : +| Resettable | -70004 | null | If present, key changes on factory| +: : : : reset : +``` + +Please see +[ProtectedData.aidl](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl) +for a full CDDL definition of the BCC. + +### `CertificateRequest` + +The full CBOR message that will be sent to the server to request certificates +is: + +```cddl +CertificateRequest = [ + DeviceInfo, + challenge : bstr, // Provided by the server + ProtectedData, // See ProtectedData.aidl + MacedKeysToSign // See IRemotelyProvisionedComponent.aidl +] + +DeviceInfo = [ + VerifiedDeviceInfo, // See DeviceInfo.aidl + UnverifiedDeviceInfo +] + +// Unverified info is anything provided by the HLOS. Subject to change out of +// step with the HAL. +UnverifiedDeviceInfo = { + ? "fingerprint" : tstr, +} + +``` + +It will be the responsibility of Keystore and the Provisioner to construct the +`CertificateRequest`. The HAL provides a method to generate the elements that +need to be constructed on the secure side, which are the tag field of +`MacedKeysToSign`, `VerifiedDeviceInfo`, and the ciphertext field of +`ProtectedData`. + +### HAL + +The remote provisioning HAL provides a simple interface that can be implemented +by multiple secure components that require remote provisioning. It would be +slightly simpler to extend the KeyMint API, but that approach would only serve +the needs of KeyMint, this is more general. + +NOTE the data structures defined in this HAL may look a little bloated and +complex. This is because the COSE data structures are fully spelled-out; we +could make it much more compact by not re-specifying the standardized elements +and instead just referencing the standard, but it seems better to fully specify +them. If the apparent complexity seems daunting, consider what the same would +look like if traditional ASN.1 DER-based structures from X.509 and related +standards were used and also fully elaborated. + +Please see the related HAL documentation directly in the source code at the +following links: + +* [IRemotelyProvisionedComponent + HAL](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/IRemotelyProvisionedComponent.aidl) +* [ProtectedData](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/ProtectedData.aidl) +* [MacedPublicKey](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/MacedPublicKey.aidl) +* [RpcHardwareInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/RpcHardwareInfo.aidl) +* [DeviceInfo](https://cs.android.com/android/platform/superproject/+/master:hardware/interfaces/security/keymint/aidl/android/hardware/security/keymint/DeviceInfo.aidl) +
diff --git a/sensors/1.0/vts/functional/Android.bp b/sensors/1.0/vts/functional/Android.bp index 274cfa7..d53179a 100644 --- a/sensors/1.0/vts/functional/Android.bp +++ b/sensors/1.0/vts/functional/Android.bp
@@ -26,7 +26,10 @@ cc_test { name: "VtsHalSensorsV1_0TargetTest", cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""], - defaults: ["VtsHalTargetTestDefaults"], + defaults: [ + "VtsHalSensorsDefaults", + "VtsHalTargetTestDefaults", + ], tidy_timeout_srcs: [ "VtsHalSensorsV1_0TargetTest.cpp", ], @@ -34,9 +37,12 @@ "SensorsHidlEnvironmentV1_0.cpp", "VtsHalSensorsV1_0TargetTest.cpp", ], + shared_libs: [ + "libbinder_ndk", + "libvndksupport", + ], static_libs: [ "android.hardware.sensors@1.0", - "VtsHalSensorsTargetTestUtils", ], test_suites: [ "general-tests",
diff --git a/sensors/2.0/vts/functional/Android.bp b/sensors/2.0/vts/functional/Android.bp index c4ec866..62eaf6b 100644 --- a/sensors/2.0/vts/functional/Android.bp +++ b/sensors/2.0/vts/functional/Android.bp
@@ -26,7 +26,10 @@ cc_test { name: "VtsHalSensorsV2_0TargetTest", cflags: ["-DLOG_TAG=\"sensors_hidl_hal_test\""], - defaults: ["VtsHalTargetTestDefaults"], + defaults: [ + "VtsHalSensorsDefaults", + "VtsHalTargetTestDefaults", + ], tidy_timeout_srcs: [ "VtsHalSensorsV2_0TargetTest.cpp", ], @@ -36,13 +39,15 @@ header_libs: [ "android.hardware.sensors@2.X-shared-utils", ], + shared_libs: [ + "libbinder_ndk", + ], static_libs: [ "android.hardware.sensors@1.0", "android.hardware.sensors@1.0-convert", "android.hardware.sensors@2.0", "android.hardware.sensors@2.1", "libfmq", - "VtsHalSensorsTargetTestUtils", "VtsHalSensorsV2_0TargetTest-lib", ], test_suites: [
diff --git a/sensors/2.1/vts/functional/Android.bp b/sensors/2.1/vts/functional/Android.bp index 3659e11..61cfd14 100644 --- a/sensors/2.1/vts/functional/Android.bp +++ b/sensors/2.1/vts/functional/Android.bp
@@ -28,7 +28,10 @@ cflags: [ "-DLOG_TAG=\"sensors_hidl_hal_test\"", ], - defaults: ["VtsHalTargetTestDefaults"], + defaults: [ + "VtsHalSensorsDefaults", + "VtsHalTargetTestDefaults", + ], srcs: [ "VtsHalSensorsV2_1TargetTest.cpp", ], @@ -41,7 +44,6 @@ "android.hardware.sensors@2.0", "android.hardware.sensors@2.1", "libfmq", - "VtsHalSensorsTargetTestUtils", "VtsHalSensorsV2_1TargetTest-lib", ], test_suites: [
diff --git a/sensors/aidl/vts/Android.bp b/sensors/aidl/vts/Android.bp index b5a5f15..f3972ec 100644 --- a/sensors/aidl/vts/Android.bp +++ b/sensors/aidl/vts/Android.bp
@@ -24,8 +24,9 @@ cc_test { name: "VtsAidlHalSensorsTargetTest", defaults: [ - "VtsHalTargetTestDefaults", "use_libaidlvintf_gtest_helper_static", + "VtsHalSensorsDefaults", + "VtsHalTargetTestDefaults", ], srcs: [ "VtsAidlHalSensorsTargetTest.cpp",
diff --git a/sensors/common/vts/utils/Android.bp b/sensors/common/vts/utils/Android.bp index 44bed6e..08b6afa 100644 --- a/sensors/common/vts/utils/Android.bp +++ b/sensors/common/vts/utils/Android.bp
@@ -23,6 +23,23 @@ default_applicable_licenses: ["hardware_interfaces_license"], } +// Prefer to use these defaults to pull in VtsHalSensorsTargetTestUtils + its +// dependencies +cc_defaults { + name: "VtsHalSensorsDefaults", + shared_libs: [ + "android.hardware.graphics.allocator-V1-ndk", + "android.hardware.graphics.common-V3-ndk", + "libbinder_ndk", + "libutils", + "libvndksupport", + ], + static_libs: [ + "libaidlcommonsupport", + "VtsHalSensorsTargetTestUtils", + ], +} + cc_library_static { name: "VtsHalSensorsTargetTestUtils", defaults: ["VtsHalTargetTestDefaults"], @@ -36,13 +53,19 @@ local_include_dirs: [ "include/sensors-vts-utils", ], + // Targets that depend on us need to also include these shared_libs: [ + "android.hardware.graphics.allocator-V1-ndk", + "android.hardware.graphics.common-V3-ndk", + "libbinder_ndk", "libutils", + "libvndksupport", ], static_libs: [ "android.hardware.sensors@1.0", "android.hardware.sensors@2.0", "android.hardware.sensors@2.1", + "libaidlcommonsupport", ], whole_static_libs: [ "android.hardware.graphics.allocator@2.0",
diff --git a/sensors/common/vts/utils/GrallocWrapper.cpp b/sensors/common/vts/utils/GrallocWrapper.cpp index 47d1f42..e6e0888 100644 --- a/sensors/common/vts/utils/GrallocWrapper.cpp +++ b/sensors/common/vts/utils/GrallocWrapper.cpp
@@ -16,6 +16,9 @@ #include "GrallocWrapper.h" +#include <aidl/android/hardware/graphics/allocator/IAllocator.h> +#include <aidlcommonsupport/NativeHandle.h> +#include <android/binder_manager.h> #include <android/hardware/graphics/allocator/2.0/IAllocator.h> #include <android/hardware/graphics/allocator/3.0/IAllocator.h> #include <android/hardware/graphics/allocator/4.0/IAllocator.h> @@ -27,8 +30,10 @@ #include <utils/Log.h> #include <cinttypes> +#include <memory> #include <type_traits> +using IAllocatorAidl = ::aidl::android::hardware::graphics::allocator::IAllocator; using IAllocator2 = ::android::hardware::graphics::allocator::V2_0::IAllocator; using IAllocator3 = ::android::hardware::graphics::allocator::V3_0::IAllocator; using IAllocator4 = ::android::hardware::graphics::allocator::V4_0::IAllocator; @@ -41,6 +46,9 @@ using Error3 = ::android::hardware::graphics::mapper::V3_0::Error; using Error4 = ::android::hardware::graphics::mapper::V4_0::Error; +using ::aidl::android::hardware::common::NativeHandle; +using ::aidl::android::hardware::graphics::allocator::AllocationResult; + using ::android::hardware::graphics::common::V1_0::BufferUsage; using ::android::hardware::graphics::common::V1_0::PixelFormat; @@ -97,10 +105,11 @@ // Since all the type and function names are the same for the things we use across the major HAL // versions, we use template magic to avoid repeating ourselves. -template <typename AllocatorT, typename MapperT> +template <typename AllocatorT, typename MapperT, + template <typename> typename AllocatorWrapperT = sp> class GrallocHalWrapper : public IGrallocHalWrapper { public: - GrallocHalWrapper(const sp<AllocatorT>& allocator, const sp<MapperT>& mapper) + GrallocHalWrapper(const AllocatorWrapperT<AllocatorT>& allocator, const sp<MapperT>& mapper) : mAllocator(allocator), mMapper(mapper) { if (mapper->isRemote()) { ALOGE("Mapper is in passthrough mode"); @@ -116,7 +125,7 @@ private: static constexpr uint64_t kBufferUsage = static_cast<uint64_t>(BufferUsage::SENSOR_DIRECT_DATA | BufferUsage::CPU_READ_OFTEN); - sp<AllocatorT> mAllocator; + AllocatorWrapperT<AllocatorT> mAllocator; sp<MapperT> mMapper; // v2.0 and v3.0 use vec<uint32_t> for BufferDescriptor, but v4.0 uses vec<uint8_t>, so use @@ -128,8 +137,34 @@ native_handle_t* importBuffer(const hidl_handle& rawHandle); }; -template <typename AllocatorT, typename MapperT> -native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::allocate(uint32_t size) { +template <> +native_handle_t* GrallocHalWrapper<IAllocatorAidl, IMapper4, std::shared_ptr>::allocate( + uint32_t size) { + constexpr uint32_t kBufferCount = 1; + BufferDescriptorT descriptor = getDescriptor(size); + native_handle_t* bufferHandle = nullptr; + + AllocationResult result; + auto status = mAllocator->allocate(descriptor, kBufferCount, &result); + if (!status.isOk()) { + status_t error = status.getExceptionCode(); + ALOGE("Failed to allocate buffer: %" PRId32, static_cast<int32_t>(error)); + } else if (result.buffers.size() != kBufferCount) { + ALOGE("Invalid buffer array size (got %zu, expected %" PRIu32 ")", result.buffers.size(), + kBufferCount); + } else { + // Convert from AIDL NativeHandle to native_handle_t to hidl_handle + hidl_handle hidlHandle; + hidlHandle.setTo(dupFromAidl(result.buffers[0]), /*shouldOwn*/ true); + bufferHandle = importBuffer(hidlHandle); + } + + return bufferHandle; +} + +template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT> +native_handle_t* GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::allocate( + uint32_t size) { constexpr uint32_t kBufferCount = 1; BufferDescriptorT descriptor = getDescriptor(size); native_handle_t* bufferHandle = nullptr; @@ -149,17 +184,18 @@ return bufferHandle; } -template <typename AllocatorT, typename MapperT> -void GrallocHalWrapper<AllocatorT, MapperT>::freeBuffer(native_handle_t* bufferHandle) { +template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT> +void GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::freeBuffer( + native_handle_t* bufferHandle) { auto error = mMapper->freeBuffer(bufferHandle); if (!error.isOk() || failed(error)) { ALOGE("Failed to free buffer %p", bufferHandle); } } -template <typename AllocatorT, typename MapperT> -typename GrallocHalWrapper<AllocatorT, MapperT>::BufferDescriptorT -GrallocHalWrapper<AllocatorT, MapperT>::getDescriptor(uint32_t size) { +template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT> +typename GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::BufferDescriptorT +GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::getDescriptor(uint32_t size) { typename MapperT::BufferDescriptorInfo descriptorInfo = { .width = size, .height = 1, @@ -181,8 +217,8 @@ return descriptor; } -template <typename AllocatorT, typename MapperT> -native_handle_t* GrallocHalWrapper<AllocatorT, MapperT>::importBuffer( +template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT> +native_handle_t* GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::importBuffer( const hidl_handle& rawHandle) { native_handle_t* bufferHandle = nullptr; @@ -198,8 +234,9 @@ return bufferHandle; } -template <typename AllocatorT, typename MapperT> -void* GrallocHalWrapper<AllocatorT, MapperT>::lock(native_handle_t* bufferHandle) { +template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT> +void* GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::lock( + native_handle_t* bufferHandle) { // Per the HAL, all-zeros Rect means the entire buffer typename MapperT::Rect accessRegion = {}; hidl_handle acquireFenceHandle; // No fence needed, already safe to lock @@ -218,8 +255,9 @@ return data; } -template <typename AllocatorT, typename MapperT> -void GrallocHalWrapper<AllocatorT, MapperT>::unlock(native_handle_t* bufferHandle) { +template <typename AllocatorT, typename MapperT, template <typename> typename AllocatorWrapperT> +void GrallocHalWrapper<AllocatorT, MapperT, AllocatorWrapperT>::unlock( + native_handle_t* bufferHandle) { mMapper->unlock(bufferHandle, [&](auto error, const hidl_handle& /*releaseFence*/) { if (failed(error)) { ALOGE("Failed to unlock buffer %p: %" PRId32, bufferHandle, @@ -234,8 +272,22 @@ sp<IAllocator4> allocator4 = IAllocator4::getService(); sp<IMapper4> mapper4 = IMapper4::getService(); - if (allocator4 != nullptr && mapper4 != nullptr) { - ALOGD("Using IAllocator/IMapper v4.0"); + const auto kAllocatorSvc = std::string(IAllocatorAidl::descriptor) + "/default"; + std::shared_ptr<IAllocatorAidl> allocatorAidl; + if (AServiceManager_isDeclared(kAllocatorSvc.c_str())) { + allocatorAidl = IAllocatorAidl::fromBinder( + ndk::SpAIBinder(AServiceManager_checkService(kAllocatorSvc.c_str()))); + } + + // As of T, AIDL Allocator is supported only with HIDL Mapper4 + // (ref: VtsHalGraphicsAllocatorAidl_TargetTest.cpp) + if (allocatorAidl != nullptr && mapper4 != nullptr) { + ALOGD("Using AIDL IAllocator + HIDL IMapper v4.0"); + mGrallocHal = std::unique_ptr<IGrallocHalWrapper>( + new GrallocHalWrapper<IAllocatorAidl, IMapper4, std::shared_ptr>(allocatorAidl, + mapper4)); + } else if (allocator4 != nullptr && mapper4 != nullptr) { + ALOGD("AIDL IAllocator not found, using HIDL IAllocator/IMapper v4.0"); mGrallocHal = std::unique_ptr<IGrallocHalWrapper>( new GrallocHalWrapper<IAllocator4, IMapper4>(allocator4, mapper4)); } else {