If possible use BLOB mode AHWB instead of ashmem for a memory object created by ANNMemory_createFromDesc

Bug: 147777318
Test: NNT_static
Change-Id: I11d3afea445149c07fd78f2d211d28e323b9c2ae
Merged-In: I11d3afea445149c07fd78f2d211d28e323b9c2ae
Merged-In: I11d3afea445149c07fd78f2d211d28e323b9c2ae
(cherry picked from commit f3a2684855562719a5c181af4b12e46c51668a12)
(cherry picked from commit 603346b6b80cd4227d070162f1b16bb5838b2102)
diff --git a/runtime/Memory.cpp b/runtime/Memory.cpp
index 9bddcd9..1f16a28 100644
--- a/runtime/Memory.cpp
+++ b/runtime/Memory.cpp
@@ -18,6 +18,10 @@
 
 #include "Memory.h"
 
+#include <android-base/scopeguard.h>
+#include <android/hardware_buffer.h>
+#include <vndk/hardware_buffer.h>
+
 #include <algorithm>
 #include <memory>
 #include <set>
@@ -256,8 +260,9 @@
 
 static int copyIBuffers(const sp<IBuffer>& src, const sp<IBuffer>& dst,
                         const MemoryValidatorBase::Metadata& srcMetadata) {
-    // TODO(xusongw): Use BLOB mode AHardwareBuffer.
-    hidl_memory hidlMemory = allocateSharedMemory(srcMetadata.logicalSize);
+    const auto [n, memory] = MemoryRuntimeAHWB::create(srcMetadata.logicalSize);
+    NN_RETURN_IF_ERROR(n);
+    const hidl_memory& hidlMemory = memory->getHidlMemory();
     if (!hidlMemory.valid()) return ANEURALNETWORKS_OUT_OF_MEMORY;
     NN_RETURN_IF_ERROR(copyIBufferToHidlMemory(src, hidlMemory));
     NN_RETURN_IF_ERROR(copyHidlMemoryToIBuffer(hidlMemory, dst, srcMetadata.dimensions));
@@ -429,20 +434,13 @@
     LOG(INFO) << "MemoryDescriptor end";
 }
 
-static const Device* selectDeviceMemoryAllocator(const MemoryDescriptor& desc) {
-    const Device* allocator = nullptr;
+static std::set<const Device*> getDevices(const MemoryDescriptor& desc) {
+    std::set<const Device*> devices;
     for (const auto* preparedModel : desc.preparedModels) {
         const auto* device = preparedModel->getDevice();
-        if (allocator == nullptr) {
-            allocator = device;
-        } else if (allocator != device) {
-            LOG(INFO) << "selectDeviceMemoryAllocator -- cannot handle multiple devices.";
-            return nullptr;
-        }
+        devices.insert(device);
     }
-    CHECK(allocator != nullptr);
-    VLOG(MEMORY) << "Using " << allocator->getName() << " as allocator.";
-    return allocator;
+    return devices;
 }
 
 int MemoryBuilder::finish() {
@@ -455,7 +453,17 @@
     if (VLOG_IS_ON(MEMORY)) {
         logMemoryDescriptorToInfo(mDesc, mOperand.value());
     }
-    mAllocator = selectDeviceMemoryAllocator(mDesc);
+    std::set<const Device*> devices = getDevices(mDesc);
+    if (devices.size() == 1) {
+        mAllocator = *devices.begin();
+        VLOG(MEMORY) << "Using " << mAllocator->getName() << " as allocator.";
+    } else {
+        LOG(INFO) << "MemoryBuilder::finish -- cannot handle multiple devices.";
+        mAllocator = nullptr;
+    }
+    mSupportsAhwb = std::all_of(devices.begin(), devices.end(), [](const auto* device) {
+        return device->getFeatureLevel() >= __ANDROID_API_Q__;
+    });
     mShouldFallback = std::none_of(mRoles.begin(), mRoles.end(), [](const auto& role) {
         const auto* cb = std::get<const CompilationBuilder*>(role);
         return cb->createdWithExplicitDeviceList();
@@ -487,11 +495,15 @@
         std::tie(n, memory) = mAllocator->allocate(mDesc, mOperand->type);
     }
 
-    // If failed, fallback to ashmem.
-    // TODO(xusongw): Use BLOB mode hardware buffer when possible.
+    // If failed, fallback to ashmem or BLOB mode AHWB.
     if (n != ANEURALNETWORKS_NO_ERROR && mShouldFallback) {
-        VLOG(MEMORY) << "MemoryBuilder::allocate -- fallback to ashmem.";
-        std::tie(n, memory) = MemoryAshmem::create(size);
+        if (mSupportsAhwb) {
+            VLOG(MEMORY) << "MemoryBuilder::allocate -- fallback to BLOB mode AHWB.";
+            std::tie(n, memory) = MemoryRuntimeAHWB::create(size);
+        } else {
+            VLOG(MEMORY) << "MemoryBuilder::allocate -- fallback to ashmem.";
+            std::tie(n, memory) = MemoryAshmem::create(size);
+        }
     }
 
     if (n == ANEURALNETWORKS_NO_ERROR) {
@@ -570,7 +582,6 @@
     AHardwareBuffer_describe(&ahwb, &bufferDesc);
     const native_handle_t* handle = AHardwareBuffer_getNativeHandle(&ahwb);
     hidl_memory hidlMemory;
-    std::unique_ptr<MemoryAHWB> memory;
     std::unique_ptr<MemoryValidatorBase> validator;
     if (bufferDesc.format == AHARDWAREBUFFER_FORMAT_BLOB) {
         hidlMemory = hidl_memory("hardware_buffer_blob", handle, bufferDesc.width);
@@ -580,10 +591,62 @@
         hidlMemory = hidl_memory("hardware_buffer", handle, 0);
         validator = std::make_unique<AHardwareBufferNonBlobValidator>();
     }
-    memory = std::make_unique<MemoryAHWB>(std::move(hidlMemory), std::move(validator));
+    auto memory = std::make_unique<MemoryAHWB>(std::move(hidlMemory), std::move(validator));
     return {ANEURALNETWORKS_NO_ERROR, std::move(memory)};
 };
 
+std::pair<int, std::unique_ptr<MemoryRuntimeAHWB>> MemoryRuntimeAHWB::create(uint32_t size) {
+    AHardwareBuffer* ahwb = nullptr;
+    const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN;
+    const AHardwareBuffer_Desc desc = {
+            .width = size,
+            .height = 1,
+            .layers = 1,
+            .format = AHARDWAREBUFFER_FORMAT_BLOB,
+            .usage = usage,
+            .stride = size,
+    };
+    int err = AHardwareBuffer_allocate(&desc, &ahwb);
+    if (err != 0 || ahwb == nullptr) {
+        LOG(ERROR) << "Failed to allocate BLOB mode AHWB.";
+        return {ANEURALNETWORKS_OP_FAILED, nullptr};
+    }
+    auto allocateGuard = base::make_scope_guard([&ahwb]() { AHardwareBuffer_release(ahwb); });
+
+    void* buffer = nullptr;
+    err = AHardwareBuffer_lock(ahwb, usage, -1, nullptr, &buffer);
+    if (err != 0 || buffer == nullptr) {
+        LOG(ERROR) << "Failed to lock BLOB mode AHWB.";
+        return {ANEURALNETWORKS_OP_FAILED, nullptr};
+    }
+    auto lockGuard = base::make_scope_guard([&ahwb]() { AHardwareBuffer_unlock(ahwb, nullptr); });
+
+    const native_handle_t* handle = AHardwareBuffer_getNativeHandle(ahwb);
+    if (handle == nullptr) {
+        LOG(ERROR) << "Failed to retrieve the native handle from the AHWB.";
+        return {ANEURALNETWORKS_OP_FAILED, nullptr};
+    }
+
+    hidl_memory hidlMemory = hidl_memory("hardware_buffer_blob", handle, desc.width);
+    auto memory = std::make_unique<MemoryRuntimeAHWB>(std::move(hidlMemory), ahwb,
+                                                      static_cast<uint8_t*>(buffer));
+    allocateGuard.Disable();
+    lockGuard.Disable();
+    return {ANEURALNETWORKS_NO_ERROR, std::move(memory)};
+}
+
+MemoryRuntimeAHWB::MemoryRuntimeAHWB(hal::hidl_memory memory, AHardwareBuffer* ahwb,
+                                     uint8_t* buffer)
+    : Memory(std::move(memory)), mAhwb(ahwb), mBuffer(buffer) {
+    CHECK(mAhwb != nullptr);
+    CHECK(mBuffer != nullptr);
+}
+
+MemoryRuntimeAHWB::~MemoryRuntimeAHWB() {
+    AHardwareBuffer_unlock(mAhwb, nullptr);
+    AHardwareBuffer_release(mAhwb);
+}
+
 std::pair<int, std::unique_ptr<MemoryFromDevice>> MemoryFromDevice::create(sp<hal::IBuffer> buffer,
                                                                            uint32_t token) {
     if (buffer == nullptr) {