From fadeb8a92046c6941db721145de3514cf6015079 Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Sun, 7 Feb 2021 00:11:13 -0800 Subject: [PATCH 1/2] Change NNAPI Memory to ref-counted SharedMemory -- hal Bug: 179906132 Test: mma Test: NeuralNetworksTest_static Test: presubmit Change-Id: I6435db906a2efe4938da18149a1fcd6d24730a95 Merged-In: I6435db906a2efe4938da18149a1fcd6d24730a95 (cherry picked from commit 79a16ebb6f42c21a21202f7b63ce372f2df15137) --- .../1.0/utils/include/nnapi/hal/1.0/Burst.h | 2 +- .../utils/include/nnapi/hal/1.0/Conversions.h | 4 +-- neuralnetworks/1.0/utils/src/Burst.cpp | 2 +- neuralnetworks/1.0/utils/src/Conversions.cpp | 11 ++++---- neuralnetworks/1.1/utils/src/Conversions.cpp | 2 +- neuralnetworks/1.2/utils/src/Conversions.cpp | 2 +- .../1.3/utils/include/nnapi/hal/1.3/Buffer.h | 4 +-- .../utils/include/nnapi/hal/1.3/Conversions.h | 4 +-- neuralnetworks/1.3/utils/src/Buffer.cpp | 4 +-- neuralnetworks/1.3/utils/src/Conversions.cpp | 8 +++--- .../include/nnapi/hal/aidl/Conversions.h | 10 +++---- neuralnetworks/aidl/utils/src/Conversions.cpp | 28 ++++++++++--------- .../vts/functional/GeneratedTestHarness.cpp | 2 +- .../common/include/nnapi/hal/CommonUtils.h | 2 +- .../common/include/nnapi/hal/HandleError.h | 13 +++++++-- .../common/include/nnapi/hal/InvalidBuffer.h | 4 +-- .../common/include/nnapi/hal/InvalidBurst.h | 2 +- .../include/nnapi/hal/ResilientBuffer.h | 4 +-- .../common/include/nnapi/hal/ResilientBurst.h | 2 +- .../utils/common/src/CommonUtils.cpp | 4 +-- .../utils/common/src/InvalidBuffer.cpp | 4 +-- .../utils/common/src/InvalidBurst.cpp | 3 +- .../utils/common/src/ResilientBuffer.cpp | 4 +-- .../utils/common/src/ResilientBurst.cpp | 3 +- neuralnetworks/utils/common/test/MockBuffer.h | 6 ++-- .../utils/common/test/ResilientBufferTest.cpp | 26 +++++++++++------ 26 files changed, 91 insertions(+), 69 deletions(-) diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h index f2cbe93c7c..832930359e 100644 --- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h +++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Burst.h @@ -41,7 +41,7 @@ class Burst final : public nn::IBurst { Burst(PrivateConstructorTag tag, nn::SharedPreparedModel preparedModel); - OptionalCacheHold cacheMemory(const nn::Memory& memory) const override; + OptionalCacheHold cacheMemory(const nn::SharedMemory& memory) const override; nn::ExecutionResult, nn::Timing>> execute( const nn::Request& request, nn::MeasureTiming measure) const override; diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Conversions.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Conversions.h index d3d933b22c..5d4bdbce82 100644 --- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Conversions.h +++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Conversions.h @@ -36,7 +36,7 @@ GeneralResult unvalidatedConvert(const hal::V1_0::Operand& operand); GeneralResult unvalidatedConvert(const hal::V1_0::Operation& operation); GeneralResult unvalidatedConvert( const hardware::hidl_vec& operandValues); -GeneralResult unvalidatedConvert(const hardware::hidl_memory& memory); +GeneralResult unvalidatedConvert(const hardware::hidl_memory& memory); GeneralResult unvalidatedConvert(const hal::V1_0::Model& model); GeneralResult unvalidatedConvert( const hal::V1_0::RequestArgument& requestArgument); @@ -65,7 +65,7 @@ nn::GeneralResult unvalidatedConvert(const nn::Operand& operand); nn::GeneralResult unvalidatedConvert(const nn::Operation& operation); nn::GeneralResult> unvalidatedConvert( const nn::Model::OperandValues& operandValues); -nn::GeneralResult unvalidatedConvert(const nn::Memory& memory); +nn::GeneralResult unvalidatedConvert(const nn::SharedMemory& memory); nn::GeneralResult unvalidatedConvert(const nn::Model& model); nn::GeneralResult unvalidatedConvert(const nn::Request::Argument& requestArgument); nn::GeneralResult unvalidatedConvert(const nn::Request::MemoryPool& memoryPool); diff --git a/neuralnetworks/1.0/utils/src/Burst.cpp b/neuralnetworks/1.0/utils/src/Burst.cpp index 384bd9b699..971ad08015 100644 --- a/neuralnetworks/1.0/utils/src/Burst.cpp +++ b/neuralnetworks/1.0/utils/src/Burst.cpp @@ -43,7 +43,7 @@ Burst::Burst(PrivateConstructorTag /*tag*/, nn::SharedPreparedModel preparedMode CHECK(kPreparedModel != nullptr); } -Burst::OptionalCacheHold Burst::cacheMemory(const nn::Memory& /*memory*/) const { +Burst::OptionalCacheHold Burst::cacheMemory(const nn::SharedMemory& /*memory*/) const { return nullptr; } diff --git a/neuralnetworks/1.0/utils/src/Conversions.cpp b/neuralnetworks/1.0/utils/src/Conversions.cpp index fde7346470..34862c00cb 100644 --- a/neuralnetworks/1.0/utils/src/Conversions.cpp +++ b/neuralnetworks/1.0/utils/src/Conversions.cpp @@ -153,7 +153,7 @@ GeneralResult unvalidatedConvert(const hidl_vec& return Model::OperandValues(operandValues.data(), operandValues.size()); } -GeneralResult unvalidatedConvert(const hidl_memory& memory) { +GeneralResult unvalidatedConvert(const hidl_memory& memory) { return createSharedMemoryFromHidlMemory(memory); } @@ -346,9 +346,10 @@ nn::GeneralResult> unvalidatedConvert( return hidl_vec(operandValues.data(), operandValues.data() + operandValues.size()); } -nn::GeneralResult unvalidatedConvert(const nn::Memory& memory) { - return hidl_memory(memory.name, NN_TRY(hal::utils::hidlHandleFromSharedHandle(memory.handle)), - memory.size); +nn::GeneralResult unvalidatedConvert(const nn::SharedMemory& memory) { + CHECK(memory != nullptr); + return hidl_memory(memory->name, NN_TRY(hal::utils::hidlHandleFromSharedHandle(memory->handle)), + memory->size); } nn::GeneralResult unvalidatedConvert(const nn::Model& model) { @@ -392,7 +393,7 @@ nn::GeneralResult unvalidatedConvert( } nn::GeneralResult unvalidatedConvert(const nn::Request::MemoryPool& memoryPool) { - return unvalidatedConvert(std::get(memoryPool)); + return unvalidatedConvert(std::get(memoryPool)); } nn::GeneralResult unvalidatedConvert(const nn::Request& request) { diff --git a/neuralnetworks/1.1/utils/src/Conversions.cpp b/neuralnetworks/1.1/utils/src/Conversions.cpp index b47f25a68c..07bf7bc88f 100644 --- a/neuralnetworks/1.1/utils/src/Conversions.cpp +++ b/neuralnetworks/1.1/utils/src/Conversions.cpp @@ -175,7 +175,7 @@ nn::GeneralResult> unvalidatedConvert( return V1_0::utils::unvalidatedConvert(operandValues); } -nn::GeneralResult unvalidatedConvert(const nn::Memory& memory) { +nn::GeneralResult unvalidatedConvert(const nn::SharedMemory& memory) { return V1_0::utils::unvalidatedConvert(memory); } diff --git a/neuralnetworks/1.2/utils/src/Conversions.cpp b/neuralnetworks/1.2/utils/src/Conversions.cpp index 062f6f712f..50556509d2 100644 --- a/neuralnetworks/1.2/utils/src/Conversions.cpp +++ b/neuralnetworks/1.2/utils/src/Conversions.cpp @@ -365,7 +365,7 @@ nn::GeneralResult> unvalidatedConvert( return V1_0::utils::unvalidatedConvert(operandValues); } -nn::GeneralResult unvalidatedConvert(const nn::Memory& memory) { +nn::GeneralResult unvalidatedConvert(const nn::SharedMemory& memory) { return V1_0::utils::unvalidatedConvert(memory); } diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h index fda79c88c1..69e87f7566 100644 --- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h +++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Buffer.h @@ -42,8 +42,8 @@ class Buffer final : public nn::IBuffer { nn::Request::MemoryDomainToken getToken() const override; - nn::GeneralResult copyTo(const nn::Memory& dst) const override; - nn::GeneralResult copyFrom(const nn::Memory& src, + nn::GeneralResult copyTo(const nn::SharedMemory& dst) const override; + nn::GeneralResult copyFrom(const nn::SharedMemory& src, const nn::Dimensions& dimensions) const override; private: diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Conversions.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Conversions.h index 74a6534aff..8e1cdb82c9 100644 --- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Conversions.h +++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Conversions.h @@ -59,7 +59,7 @@ GeneralResult convert( GeneralResult convert(const hal::V1_3::ErrorStatus& errorStatus); GeneralResult convert(const hardware::hidl_handle& handle); -GeneralResult convert(const hardware::hidl_memory& memory); +GeneralResult convert(const hardware::hidl_memory& memory); GeneralResult> convert( const hardware::hidl_vec& bufferRoles); @@ -100,7 +100,7 @@ nn::GeneralResult convert( nn::GeneralResult convert(const nn::ErrorStatus& errorStatus); nn::GeneralResult convert(const nn::SharedHandle& handle); -nn::GeneralResult convert(const nn::Memory& memory); +nn::GeneralResult convert(const nn::SharedMemory& memory); nn::GeneralResult> convert(const std::vector& bufferRoles); nn::GeneralResult convert(const nn::DeviceStatus& deviceStatus); diff --git a/neuralnetworks/1.3/utils/src/Buffer.cpp b/neuralnetworks/1.3/utils/src/Buffer.cpp index 614033e268..ada526573b 100644 --- a/neuralnetworks/1.3/utils/src/Buffer.cpp +++ b/neuralnetworks/1.3/utils/src/Buffer.cpp @@ -61,7 +61,7 @@ nn::Request::MemoryDomainToken Buffer::getToken() const { return kToken; } -nn::GeneralResult Buffer::copyTo(const nn::Memory& dst) const { +nn::GeneralResult Buffer::copyTo(const nn::SharedMemory& dst) const { const auto hidlDst = NN_TRY(convert(dst)); const auto ret = kBuffer->copyTo(hidlDst); @@ -71,7 +71,7 @@ nn::GeneralResult Buffer::copyTo(const nn::Memory& dst) const { return {}; } -nn::GeneralResult Buffer::copyFrom(const nn::Memory& src, +nn::GeneralResult Buffer::copyFrom(const nn::SharedMemory& src, const nn::Dimensions& dimensions) const { const auto hidlSrc = NN_TRY(convert(src)); const auto hidlDimensions = hidl_vec(dimensions); diff --git a/neuralnetworks/1.3/utils/src/Conversions.cpp b/neuralnetworks/1.3/utils/src/Conversions.cpp index 8b7db2b90e..d96588e34c 100644 --- a/neuralnetworks/1.3/utils/src/Conversions.cpp +++ b/neuralnetworks/1.3/utils/src/Conversions.cpp @@ -352,7 +352,7 @@ GeneralResult convert(const hardware::hidl_handle& handle) { return validatedConvert(handle); } -GeneralResult convert(const hardware::hidl_memory& memory) { +GeneralResult convert(const hardware::hidl_memory& memory) { return validatedConvert(memory); } @@ -386,7 +386,7 @@ nn::GeneralResult unvalidatedConvert(const nn::SharedHandle& handle return V1_2::utils::unvalidatedConvert(handle); } -nn::GeneralResult unvalidatedConvert(const nn::Memory& memory) { +nn::GeneralResult unvalidatedConvert(const nn::SharedMemory& memory) { return V1_0::utils::unvalidatedConvert(memory); } @@ -424,7 +424,7 @@ nn::GeneralResult>> unvalidatedConvert( return unvalidatedConvertVec(arguments); } -nn::GeneralResult makeMemoryPool(const nn::Memory& memory) { +nn::GeneralResult makeMemoryPool(const nn::SharedMemory& memory) { Request::MemoryPool ret; ret.hidlMemory(NN_TRY(unvalidatedConvert(memory))); return ret; @@ -677,7 +677,7 @@ nn::GeneralResult convert(const nn::SharedHandle& handle) { return validatedConvert(handle); } -nn::GeneralResult convert(const nn::Memory& memory) { +nn::GeneralResult convert(const nn::SharedMemory& memory) { return validatedConvert(memory); } diff --git a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h index 35de5befd0..1b2f69c245 100644 --- a/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h +++ b/neuralnetworks/aidl/utils/include/nnapi/hal/aidl/Conversions.h @@ -79,7 +79,7 @@ GeneralResult unvalidatedConvert(const std::vector unvalidatedConvert(const aidl_hal::Subgraph& subgraph); GeneralResult unvalidatedConvert(const aidl_hal::OutputShape& outputShape); GeneralResult unvalidatedConvert(bool measureTiming); -GeneralResult unvalidatedConvert(const aidl_hal::Memory& memory); +GeneralResult unvalidatedConvert(const aidl_hal::Memory& memory); GeneralResult unvalidatedConvert(const aidl_hal::Timing& timing); GeneralResult unvalidatedConvert(const aidl_hal::BufferDesc& bufferDesc); GeneralResult unvalidatedConvert(const aidl_hal::BufferRole& bufferRole); @@ -99,7 +99,7 @@ GeneralResult unvalidatedConvert( GeneralResult convert( const aidl_hal::ExecutionPreference& executionPreference); -GeneralResult convert(const aidl_hal::Memory& memory); +GeneralResult convert(const aidl_hal::Memory& memory); GeneralResult convert(const aidl_hal::Model& model); GeneralResult convert(const aidl_hal::Operand& operand); GeneralResult convert(const aidl_hal::OperandType& operandType); @@ -108,7 +108,7 @@ GeneralResult convert(const aidl_hal::RequestMemoryPool& me GeneralResult convert(const aidl_hal::Request& request); GeneralResult> convert(const std::vector& outputShapes); -GeneralResult> convert(const std::vector& memories); +GeneralResult> convert(const std::vector& memories); GeneralResult> toUnsigned(const std::vector& vec); @@ -118,11 +118,11 @@ namespace aidl::android::hardware::neuralnetworks::utils { namespace nn = ::android::nn; -nn::GeneralResult unvalidatedConvert(const nn::Memory& memory); +nn::GeneralResult unvalidatedConvert(const nn::SharedMemory& memory); nn::GeneralResult unvalidatedConvert(const nn::OutputShape& outputShape); nn::GeneralResult unvalidatedConvert(const nn::ErrorStatus& errorStatus); -nn::GeneralResult convert(const nn::Memory& memory); +nn::GeneralResult convert(const nn::SharedMemory& memory); nn::GeneralResult convert(const nn::ErrorStatus& errorStatus); nn::GeneralResult> convert( const std::vector& outputShapes); diff --git a/neuralnetworks/aidl/utils/src/Conversions.cpp b/neuralnetworks/aidl/utils/src/Conversions.cpp index 0e93b02a1e..486d01bc51 100644 --- a/neuralnetworks/aidl/utils/src/Conversions.cpp +++ b/neuralnetworks/aidl/utils/src/Conversions.cpp @@ -53,6 +53,8 @@ constexpr auto kVersion = android::nn::Version::ANDROID_S; namespace android::nn { namespace { +using ::aidl::android::hardware::common::NativeHandle; + constexpr auto validOperandType(nn::OperandType operandType) { switch (operandType) { case nn::OperandType::FLOAT32: @@ -316,13 +318,13 @@ GeneralResult unvalidatedConvert(bool measureTiming) { return measureTiming ? MeasureTiming::YES : MeasureTiming::NO; } -GeneralResult unvalidatedConvert(const aidl_hal::Memory& memory) { +GeneralResult unvalidatedConvert(const aidl_hal::Memory& memory) { VERIFY_NON_NEGATIVE(memory.size) << "Memory size must not be negative"; - return Memory{ + return std::make_shared(Memory{ .handle = NN_TRY(unvalidatedConvert(memory.handle)), .size = static_cast(memory.size), .name = memory.name, - }; + }); } GeneralResult unvalidatedConvert(const std::vector& operandValues) { @@ -397,8 +399,7 @@ GeneralResult unvalidatedConvert( return static_cast(executionPreference); } -GeneralResult unvalidatedConvert( - const ::aidl::android::hardware::common::NativeHandle& aidlNativeHandle) { +GeneralResult unvalidatedConvert(const NativeHandle& aidlNativeHandle) { std::vector fds; fds.reserve(aidlNativeHandle.fds.size()); for (const auto& fd : aidlNativeHandle.fds) { @@ -422,7 +423,7 @@ GeneralResult convert( return validatedConvert(executionPreference); } -GeneralResult convert(const aidl_hal::Memory& operand) { +GeneralResult convert(const aidl_hal::Memory& operand) { return validatedConvert(operand); } @@ -454,7 +455,7 @@ GeneralResult> convert(const std::vector> convert(const std::vector& memories) { +GeneralResult> convert(const std::vector& memories) { return validatedConvert(memories); } @@ -525,14 +526,15 @@ nn::GeneralResult unvalidatedConvert(const nn::SharedHandl return aidlNativeHandle; } -nn::GeneralResult unvalidatedConvert(const nn::Memory& memory) { - if (memory.size > std::numeric_limits::max()) { +nn::GeneralResult unvalidatedConvert(const nn::SharedMemory& memory) { + CHECK(memory != nullptr); + if (memory->size > std::numeric_limits::max()) { return NN_ERROR() << "Memory size doesn't fit into int64_t."; } return Memory{ - .handle = NN_TRY(unvalidatedConvert(memory.handle)), - .size = static_cast(memory.size), - .name = memory.name, + .handle = NN_TRY(unvalidatedConvert(memory->handle)), + .size = static_cast(memory->size), + .name = memory->name, }; } @@ -558,7 +560,7 @@ nn::GeneralResult unvalidatedConvert(const nn::OutputShape& outputS .isSufficient = outputShape.isSufficient}; } -nn::GeneralResult convert(const nn::Memory& memory) { +nn::GeneralResult convert(const nn::SharedMemory& memory) { return validatedConvert(memory); } diff --git a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp index 86d5f3f8d3..4beb828253 100644 --- a/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp +++ b/neuralnetworks/aidl/vts/functional/GeneratedTestHarness.cpp @@ -266,7 +266,7 @@ Model createModel(const TestModel& testModel) { copyTestBuffers(constCopies, operandValues.data()); // Shared memory. - std::vector pools = {}; + std::vector pools = {}; if (constRefSize > 0) { const auto pool = nn::createSharedMemory(constRefSize).value(); pools.push_back(pool); diff --git a/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h b/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h index fef9d9cfb5..b13785dcd9 100644 --- a/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h +++ b/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h @@ -74,7 +74,7 @@ nn::GeneralResult unflushDataFromSharedToPointer( std::vector countNumberOfConsumers(size_t numberOfOperands, const std::vector& operations); -nn::GeneralResult createSharedMemoryFromHidlMemory(const hidl_memory& memory); +nn::GeneralResult createSharedMemoryFromHidlMemory(const hidl_memory& memory); nn::GeneralResult hidlHandleFromSharedHandle(const nn::SharedHandle& handle); nn::GeneralResult sharedHandleFromNativeHandle(const native_handle_t* handle); diff --git a/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h b/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h index 95a20a8f80..209b66304c 100644 --- a/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h +++ b/neuralnetworks/utils/common/include/nnapi/hal/HandleError.h @@ -14,6 +14,9 @@ * limitations under the License. */ +#ifndef ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_HANDLE_ERROR_H +#define ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_HANDLE_ERROR_H + #include #include #include @@ -50,7 +53,8 @@ nn::GeneralResult handleTransportError(const hardware::Return& ret) }) template -nn::GeneralResult makeGeneralFailure(nn::Result result, nn::ErrorStatus status) { +nn::GeneralResult makeGeneralFailure( + nn::Result result, nn::ErrorStatus status = nn::ErrorStatus::GENERAL_FAILURE) { if (!result.has_value()) { return nn::error(status) << std::move(result).error(); } @@ -75,7 +79,8 @@ nn::ExecutionResult makeExecutionFailure(nn::GeneralResult result) { } template -nn::ExecutionResult makeExecutionFailure(nn::Result result, nn::ErrorStatus status) { +nn::ExecutionResult makeExecutionFailure( + nn::Result result, nn::ErrorStatus status = nn::ErrorStatus::GENERAL_FAILURE) { return makeExecutionFailure(makeGeneralFailure(result, status)); } @@ -86,4 +91,6 @@ nn::ExecutionResult makeExecutionFailure(nn::Result result, nn::Erro } else \ return NN_ERROR(canonical) -} // namespace android::hardware::neuralnetworks::utils \ No newline at end of file +} // namespace android::hardware::neuralnetworks::utils + +#endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_UTILS_COMMON_HANDLE_ERROR_H diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBuffer.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBuffer.h index 8c04b8887b..0e98c2eea2 100644 --- a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBuffer.h +++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBuffer.h @@ -31,9 +31,9 @@ class InvalidBuffer final : public nn::IBuffer { public: nn::Request::MemoryDomainToken getToken() const override; - nn::GeneralResult copyTo(const nn::Memory& dst) const override; + nn::GeneralResult copyTo(const nn::SharedMemory& dst) const override; - nn::GeneralResult copyFrom(const nn::Memory& src, + nn::GeneralResult copyFrom(const nn::SharedMemory& src, const nn::Dimensions& dimensions) const override; }; diff --git a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h index 83e60b6a25..996858cd55 100644 --- a/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h +++ b/neuralnetworks/utils/common/include/nnapi/hal/InvalidBurst.h @@ -29,7 +29,7 @@ namespace android::hardware::neuralnetworks::utils { class InvalidBurst final : public nn::IBurst { public: - OptionalCacheHold cacheMemory(const nn::Memory& memory) const override; + OptionalCacheHold cacheMemory(const nn::SharedMemory& memory) const override; nn::ExecutionResult, nn::Timing>> execute( const nn::Request& request, nn::MeasureTiming measure) const override; diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBuffer.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBuffer.h index d2c2469403..c8ca6f2d36 100644 --- a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBuffer.h +++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBuffer.h @@ -46,9 +46,9 @@ class ResilientBuffer final : public nn::IBuffer { nn::Request::MemoryDomainToken getToken() const override; - nn::GeneralResult copyTo(const nn::Memory& dst) const override; + nn::GeneralResult copyTo(const nn::SharedMemory& dst) const override; - nn::GeneralResult copyFrom(const nn::Memory& src, + nn::GeneralResult copyFrom(const nn::SharedMemory& src, const nn::Dimensions& dimensions) const override; private: diff --git a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h index 0df287f2f8..3b87330872 100644 --- a/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h +++ b/neuralnetworks/utils/common/include/nnapi/hal/ResilientBurst.h @@ -44,7 +44,7 @@ class ResilientBurst final : public nn::IBurst, nn::SharedBurst getBurst() const; nn::GeneralResult recover(const nn::IBurst* failingBurst) const; - OptionalCacheHold cacheMemory(const nn::Memory& memory) const override; + OptionalCacheHold cacheMemory(const nn::SharedMemory& memory) const override; nn::ExecutionResult, nn::Timing>> execute( const nn::Request& request, nn::MeasureTiming measure) const override; diff --git a/neuralnetworks/utils/common/src/CommonUtils.cpp b/neuralnetworks/utils/common/src/CommonUtils.cpp index c04c8dfa8b..90215630c9 100644 --- a/neuralnetworks/utils/common/src/CommonUtils.cpp +++ b/neuralnetworks/utils/common/src/CommonUtils.cpp @@ -203,13 +203,13 @@ nn::GeneralResult> flushDataFromPointe nn::GeneralResult unflushDataFromSharedToPointer( const nn::Request& request, const std::optional& maybeRequestInShared) { if (!maybeRequestInShared.has_value() || maybeRequestInShared->pools.empty() || - !std::holds_alternative(maybeRequestInShared->pools.back())) { + !std::holds_alternative(maybeRequestInShared->pools.back())) { return {}; } const auto& requestInShared = *maybeRequestInShared; // Map the memory. - const auto& outputMemory = std::get(requestInShared.pools.back()); + const auto& outputMemory = std::get(requestInShared.pools.back()); const auto [pointer, size, context] = NN_TRY(map(outputMemory)); const uint8_t* constantPointer = std::visit([](const auto& o) { return static_cast(o); }, pointer); diff --git a/neuralnetworks/utils/common/src/InvalidBuffer.cpp b/neuralnetworks/utils/common/src/InvalidBuffer.cpp index c6f75d7137..e73001dee5 100644 --- a/neuralnetworks/utils/common/src/InvalidBuffer.cpp +++ b/neuralnetworks/utils/common/src/InvalidBuffer.cpp @@ -30,11 +30,11 @@ nn::Request::MemoryDomainToken InvalidBuffer::getToken() const { return nn::Request::MemoryDomainToken{}; } -nn::GeneralResult InvalidBuffer::copyTo(const nn::Memory& /*dst*/) const { +nn::GeneralResult InvalidBuffer::copyTo(const nn::SharedMemory& /*dst*/) const { return NN_ERROR() << "InvalidBuffer"; } -nn::GeneralResult InvalidBuffer::copyFrom(const nn::Memory& /*src*/, +nn::GeneralResult InvalidBuffer::copyFrom(const nn::SharedMemory& /*src*/, const nn::Dimensions& /*dimensions*/) const { return NN_ERROR() << "InvalidBuffer"; } diff --git a/neuralnetworks/utils/common/src/InvalidBurst.cpp b/neuralnetworks/utils/common/src/InvalidBurst.cpp index 4ca6603eb7..81ca18d259 100644 --- a/neuralnetworks/utils/common/src/InvalidBurst.cpp +++ b/neuralnetworks/utils/common/src/InvalidBurst.cpp @@ -26,7 +26,8 @@ namespace android::hardware::neuralnetworks::utils { -InvalidBurst::OptionalCacheHold InvalidBurst::cacheMemory(const nn::Memory& /*memory*/) const { +InvalidBurst::OptionalCacheHold InvalidBurst::cacheMemory( + const nn::SharedMemory& /*memory*/) const { return nullptr; } diff --git a/neuralnetworks/utils/common/src/ResilientBuffer.cpp b/neuralnetworks/utils/common/src/ResilientBuffer.cpp index 47abbe268f..1904375fd4 100644 --- a/neuralnetworks/utils/common/src/ResilientBuffer.cpp +++ b/neuralnetworks/utils/common/src/ResilientBuffer.cpp @@ -99,12 +99,12 @@ nn::Request::MemoryDomainToken ResilientBuffer::getToken() const { return getBuffer()->getToken(); } -nn::GeneralResult ResilientBuffer::copyTo(const nn::Memory& dst) const { +nn::GeneralResult ResilientBuffer::copyTo(const nn::SharedMemory& dst) const { const auto fn = [&dst](const nn::IBuffer& buffer) { return buffer.copyTo(dst); }; return protect(*this, fn); } -nn::GeneralResult ResilientBuffer::copyFrom(const nn::Memory& src, +nn::GeneralResult ResilientBuffer::copyFrom(const nn::SharedMemory& src, const nn::Dimensions& dimensions) const { const auto fn = [&src, &dimensions](const nn::IBuffer& buffer) { return buffer.copyFrom(src, dimensions); diff --git a/neuralnetworks/utils/common/src/ResilientBurst.cpp b/neuralnetworks/utils/common/src/ResilientBurst.cpp index 0d3cb33a98..5ca868bc9a 100644 --- a/neuralnetworks/utils/common/src/ResilientBurst.cpp +++ b/neuralnetworks/utils/common/src/ResilientBurst.cpp @@ -94,7 +94,8 @@ nn::GeneralResult ResilientBurst::recover(const nn::IBurst* fai return mBurst; } -ResilientBurst::OptionalCacheHold ResilientBurst::cacheMemory(const nn::Memory& memory) const { +ResilientBurst::OptionalCacheHold ResilientBurst::cacheMemory( + const nn::SharedMemory& memory) const { return getBurst()->cacheMemory(memory); } diff --git a/neuralnetworks/utils/common/test/MockBuffer.h b/neuralnetworks/utils/common/test/MockBuffer.h index c5405fb837..59d57007ae 100644 --- a/neuralnetworks/utils/common/test/MockBuffer.h +++ b/neuralnetworks/utils/common/test/MockBuffer.h @@ -27,9 +27,9 @@ namespace android::nn { class MockBuffer final : public IBuffer { public: MOCK_METHOD(Request::MemoryDomainToken, getToken, (), (const, override)); - MOCK_METHOD(GeneralResult, copyTo, (const Memory& dst), (const, override)); - MOCK_METHOD(GeneralResult, copyFrom, (const Memory& src, const Dimensions& dimensions), - (const, override)); + MOCK_METHOD(GeneralResult, copyTo, (const SharedMemory& dst), (const, override)); + MOCK_METHOD(GeneralResult, copyFrom, + (const SharedMemory& src, const Dimensions& dimensions), (const, override)); }; } // namespace android::nn diff --git a/neuralnetworks/utils/common/test/ResilientBufferTest.cpp b/neuralnetworks/utils/common/test/ResilientBufferTest.cpp index deb9b7cf21..7afd0203bb 100644 --- a/neuralnetworks/utils/common/test/ResilientBufferTest.cpp +++ b/neuralnetworks/utils/common/test/ResilientBufferTest.cpp @@ -15,9 +15,11 @@ */ #include +#include #include #include #include +#include #include #include #include "MockBuffer.h" @@ -113,7 +115,8 @@ TEST(ResilientBufferTest, copyTo) { EXPECT_CALL(*mockBuffer, copyTo(_)).Times(1).WillOnce(Return(kNoError)); // run test - const auto result = buffer->copyTo({}); + const nn::SharedMemory memory = std::make_shared(); + const auto result = buffer->copyTo(memory); // verify result ASSERT_TRUE(result.has_value()) @@ -126,7 +129,8 @@ TEST(ResilientBufferTest, copyToError) { EXPECT_CALL(*mockBuffer, copyTo(_)).Times(1).WillOnce(kReturnGeneralFailure); // run test - const auto result = buffer->copyTo({}); + const nn::SharedMemory memory = std::make_shared(); + const auto result = buffer->copyTo(memory); // verify result ASSERT_FALSE(result.has_value()); @@ -140,7 +144,8 @@ TEST(ResilientBufferTest, copyToDeadObjectFailedRecovery) { EXPECT_CALL(*mockBufferFactory, Call()).Times(1).WillOnce(kReturnGeneralFailure); // run test - const auto result = buffer->copyTo({}); + const nn::SharedMemory memory = std::make_shared(); + const auto result = buffer->copyTo(memory); // verify result ASSERT_FALSE(result.has_value()); @@ -156,7 +161,8 @@ TEST(ResilientBufferTest, copyToDeadObjectSuccessfulRecovery) { EXPECT_CALL(*mockBufferFactory, Call()).Times(1).WillOnce(Return(recoveredMockBuffer)); // run test - const auto result = buffer->copyTo({}); + const nn::SharedMemory memory = std::make_shared(); + const auto result = buffer->copyTo(memory); // verify result ASSERT_TRUE(result.has_value()) @@ -169,7 +175,8 @@ TEST(ResilientBufferTest, copyFrom) { EXPECT_CALL(*mockBuffer, copyFrom(_, _)).Times(1).WillOnce(Return(kNoError)); // run test - const auto result = buffer->copyFrom({}, {}); + const nn::SharedMemory memory = std::make_shared(); + const auto result = buffer->copyFrom(memory, {}); // verify result ASSERT_TRUE(result.has_value()) @@ -182,7 +189,8 @@ TEST(ResilientBufferTest, copyFromError) { EXPECT_CALL(*mockBuffer, copyFrom(_, _)).Times(1).WillOnce(kReturnGeneralFailure); // run test - const auto result = buffer->copyFrom({}, {}); + const nn::SharedMemory memory = std::make_shared(); + const auto result = buffer->copyFrom(memory, {}); // verify result ASSERT_FALSE(result.has_value()); @@ -196,7 +204,8 @@ TEST(ResilientBufferTest, copyFromDeadObjectFailedRecovery) { EXPECT_CALL(*mockBufferFactory, Call()).Times(1).WillOnce(kReturnGeneralFailure); // run test - const auto result = buffer->copyFrom({}, {}); + const nn::SharedMemory memory = std::make_shared(); + const auto result = buffer->copyFrom(memory, {}); // verify result ASSERT_FALSE(result.has_value()); @@ -212,7 +221,8 @@ TEST(ResilientBufferTest, copyFromDeadObjectSuccessfulRecovery) { EXPECT_CALL(*mockBufferFactory, Call()).Times(1).WillOnce(Return(recoveredMockBuffer)); // run test - const auto result = buffer->copyFrom({}, {}); + const nn::SharedMemory memory = std::make_shared(); + const auto result = buffer->copyFrom(memory, {}); // verify result ASSERT_TRUE(result.has_value()) From ab2f482af37540942e2d1702e062a29575e8178d Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Mon, 8 Feb 2021 00:05:07 -0800 Subject: [PATCH 2/2] Store AHWB in NN canonical memory type -- hal Prior to this CL, the canonical memory type only held a SharedHandle, which mirrors the behavior of native_handle_t/hidl_handle. This means memory types including AHardwareBuffer were stored as this SharedHandle type. With this CL, the canonical memory type is stored directly as AHardwareBuffer to avoid using non-NDK AHardwareBuffer calls in the NN runtime. Bug: 179906132 Test: mma Test: NeuralNetworksTest_static Test: presubmit Change-Id: I394071c193d15ac0c90ac47e5a2a9a79c635db6c Merged-In: I394071c193d15ac0c90ac47e5a2a9a79c635db6c (cherry picked from commit bbe43d950e981cfb5c06622c8f80b57ab60b0497) --- neuralnetworks/1.0/utils/src/Conversions.cpp | 6 +- neuralnetworks/1.2/utils/src/Conversions.cpp | 11 +- neuralnetworks/1.3/utils/src/Conversions.cpp | 2 +- neuralnetworks/aidl/utils/Android.bp | 4 +- neuralnetworks/aidl/utils/src/Conversions.cpp | 197 +++++++++++++++--- neuralnetworks/aidl/vts/functional/Utils.cpp | 3 +- neuralnetworks/utils/common/Android.bp | 2 + .../common/include/nnapi/hal/CommonUtils.h | 6 +- .../utils/common/src/CommonUtils.cpp | 121 +++++++++-- 9 files changed, 299 insertions(+), 53 deletions(-) diff --git a/neuralnetworks/1.0/utils/src/Conversions.cpp b/neuralnetworks/1.0/utils/src/Conversions.cpp index 34862c00cb..7a099cfd49 100644 --- a/neuralnetworks/1.0/utils/src/Conversions.cpp +++ b/neuralnetworks/1.0/utils/src/Conversions.cpp @@ -154,7 +154,7 @@ GeneralResult unvalidatedConvert(const hidl_vec& } GeneralResult unvalidatedConvert(const hidl_memory& memory) { - return createSharedMemoryFromHidlMemory(memory); + return hal::utils::createSharedMemoryFromHidlMemory(memory); } GeneralResult unvalidatedConvert(const hal::V1_0::Model& model) { @@ -347,9 +347,7 @@ nn::GeneralResult> unvalidatedConvert( } nn::GeneralResult unvalidatedConvert(const nn::SharedMemory& memory) { - CHECK(memory != nullptr); - return hidl_memory(memory->name, NN_TRY(hal::utils::hidlHandleFromSharedHandle(memory->handle)), - memory->size); + return hal::utils::createHidlMemoryFromSharedMemory(memory); } nn::GeneralResult unvalidatedConvert(const nn::Model& model) { diff --git a/neuralnetworks/1.2/utils/src/Conversions.cpp b/neuralnetworks/1.2/utils/src/Conversions.cpp index 50556509d2..7ae483ede2 100644 --- a/neuralnetworks/1.2/utils/src/Conversions.cpp +++ b/neuralnetworks/1.2/utils/src/Conversions.cpp @@ -304,7 +304,11 @@ GeneralResult unvalidatedConvert( } GeneralResult unvalidatedConvert(const hidl_handle& hidlHandle) { - return hal::utils::sharedHandleFromNativeHandle(hidlHandle.getNativeHandle()); + if (hidlHandle.getNativeHandle() == nullptr) { + return nullptr; + } + auto handle = NN_TRY(hal::utils::sharedHandleFromNativeHandle(hidlHandle.getNativeHandle())); + return std::make_shared(std::move(handle)); } GeneralResult convert(const hal::V1_2::DeviceType& deviceType) { @@ -588,7 +592,10 @@ nn::GeneralResult unvalidatedConvert( } nn::GeneralResult unvalidatedConvert(const nn::SharedHandle& handle) { - return hal::utils::hidlHandleFromSharedHandle(handle); + if (handle == nullptr) { + return {}; + } + return hal::utils::hidlHandleFromSharedHandle(*handle); } nn::GeneralResult convert(const nn::DeviceType& deviceType) { diff --git a/neuralnetworks/1.3/utils/src/Conversions.cpp b/neuralnetworks/1.3/utils/src/Conversions.cpp index d96588e34c..6e74a6239d 100644 --- a/neuralnetworks/1.3/utils/src/Conversions.cpp +++ b/neuralnetworks/1.3/utils/src/Conversions.cpp @@ -261,7 +261,7 @@ GeneralResult unvalidatedConvert( using Discriminator = hal::V1_3::Request::MemoryPool::hidl_discriminator; switch (memoryPool.getDiscriminator()) { case Discriminator::hidlMemory: - return createSharedMemoryFromHidlMemory(memoryPool.hidlMemory()); + return hal::utils::createSharedMemoryFromHidlMemory(memoryPool.hidlMemory()); case Discriminator::token: return static_cast(memoryPool.token()); } diff --git a/neuralnetworks/aidl/utils/Android.bp b/neuralnetworks/aidl/utils/Android.bp index 56017da52d..147d401201 100644 --- a/neuralnetworks/aidl/utils/Android.bp +++ b/neuralnetworks/aidl/utils/Android.bp @@ -21,12 +21,14 @@ cc_library_static { local_include_dirs: ["include/nnapi/hal/aidl/"], export_include_dirs: ["include"], static_libs: [ + "libarect", "neuralnetworks_types", "neuralnetworks_utils_hal_common", ], shared_libs: [ - "libhidlbase", "android.hardware.neuralnetworks-V1-ndk_platform", "libbinder_ndk", + "libhidlbase", + "libnativewindow", ], } diff --git a/neuralnetworks/aidl/utils/src/Conversions.cpp b/neuralnetworks/aidl/utils/src/Conversions.cpp index 486d01bc51..db3504bb74 100644 --- a/neuralnetworks/aidl/utils/src/Conversions.cpp +++ b/neuralnetworks/aidl/utils/src/Conversions.cpp @@ -18,6 +18,8 @@ #include #include +#include +#include #include #include #include @@ -27,6 +29,7 @@ #include #include #include +#include #include #include @@ -127,6 +130,61 @@ GeneralResult>> validatedConvert( return canonical; } +GeneralResult unvalidatedConvertHelper(const NativeHandle& aidlNativeHandle) { + std::vector fds; + fds.reserve(aidlNativeHandle.fds.size()); + for (const auto& fd : aidlNativeHandle.fds) { + const int dupFd = dup(fd.get()); + if (dupFd == -1) { + // TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return + // here? + return NN_ERROR() << "Failed to dup the fd"; + } + fds.emplace_back(dupFd); + } + + return Handle{.fds = std::move(fds), .ints = aidlNativeHandle.ints}; +} + +struct NativeHandleDeleter { + void operator()(native_handle_t* handle) const { + if (handle) { + native_handle_close(handle); + native_handle_delete(handle); + } + } +}; + +using UniqueNativeHandle = std::unique_ptr; + +static nn::GeneralResult nativeHandleFromAidlHandle( + const NativeHandle& handle) { + std::vector fds; + fds.reserve(handle.fds.size()); + for (const auto& fd : handle.fds) { + const int dupFd = dup(fd.get()); + if (dupFd == -1) { + return NN_ERROR() << "Failed to dup the fd"; + } + fds.emplace_back(dupFd); + } + + constexpr size_t kIntMax = std::numeric_limits::max(); + CHECK_LE(handle.fds.size(), kIntMax); + CHECK_LE(handle.ints.size(), kIntMax); + native_handle_t* nativeHandle = native_handle_create(static_cast(handle.fds.size()), + static_cast(handle.ints.size())); + if (nativeHandle == nullptr) { + return NN_ERROR() << "Failed to create native_handle"; + } + for (size_t i = 0; i < fds.size(); ++i) { + nativeHandle->data[i] = fds[i].release(); + } + std::copy(handle.ints.begin(), handle.ints.end(), &nativeHandle->data[nativeHandle->numFds]); + + return UniqueNativeHandle(nativeHandle); +} + } // anonymous namespace GeneralResult unvalidatedConvert(const aidl_hal::OperandType& operandType) { @@ -318,10 +376,64 @@ GeneralResult unvalidatedConvert(bool measureTiming) { return measureTiming ? MeasureTiming::YES : MeasureTiming::NO; } +static uint32_t roundUpToMultiple(uint32_t value, uint32_t multiple) { + return (value + multiple - 1) / multiple * multiple; +} + GeneralResult unvalidatedConvert(const aidl_hal::Memory& memory) { VERIFY_NON_NEGATIVE(memory.size) << "Memory size must not be negative"; + if (memory.size > std::numeric_limits::max()) { + return NN_ERROR() << "Memory: size must be <= std::numeric_limits::max()"; + } + + if (memory.name != "hardware_buffer_blob") { + return std::make_shared(Memory{ + .handle = NN_TRY(unvalidatedConvertHelper(memory.handle)), + .size = static_cast(memory.size), + .name = memory.name, + }); + } + + const auto size = static_cast(memory.size); + const auto format = AHARDWAREBUFFER_FORMAT_BLOB; + const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN; + const uint32_t width = size; + const uint32_t height = 1; // height is always 1 for BLOB mode AHardwareBuffer. + const uint32_t layers = 1; // layers is always 1 for BLOB mode AHardwareBuffer. + + const UniqueNativeHandle handle = NN_TRY(nativeHandleFromAidlHandle(memory.handle)); + const native_handle_t* nativeHandle = handle.get(); + + // AHardwareBuffer_createFromHandle() might fail because an allocator + // expects a specific stride value. In that case, we try to guess it by + // aligning the width to small powers of 2. + // TODO(b/174120849): Avoid stride assumptions. + AHardwareBuffer* hardwareBuffer = nullptr; + status_t status = UNKNOWN_ERROR; + for (uint32_t alignment : {1, 4, 32, 64, 128, 2, 8, 16}) { + const uint32_t stride = roundUpToMultiple(width, alignment); + AHardwareBuffer_Desc desc{ + .width = width, + .height = height, + .layers = layers, + .format = format, + .usage = usage, + .stride = stride, + }; + status = AHardwareBuffer_createFromHandle(&desc, nativeHandle, + AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, + &hardwareBuffer); + if (status == NO_ERROR) { + break; + } + } + if (status != NO_ERROR) { + return NN_ERROR(ErrorStatus::GENERAL_FAILURE) + << "Can't create AHardwareBuffer from handle. Error: " << status; + } + return std::make_shared(Memory{ - .handle = NN_TRY(unvalidatedConvert(memory.handle)), + .handle = HardwareBufferHandle(hardwareBuffer, /*takeOwnership=*/true), .size = static_cast(memory.size), .name = memory.name, }); @@ -400,22 +512,7 @@ GeneralResult unvalidatedConvert( } GeneralResult unvalidatedConvert(const NativeHandle& aidlNativeHandle) { - std::vector fds; - fds.reserve(aidlNativeHandle.fds.size()); - for (const auto& fd : aidlNativeHandle.fds) { - int dupFd = dup(fd.get()); - if (dupFd == -1) { - // TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return - // here? - return NN_ERROR() << "Failed to dup the fd"; - } - fds.emplace_back(dupFd); - } - - return std::make_shared(Handle{ - .fds = std::move(fds), - .ints = aidlNativeHandle.ints, - }); + return std::make_shared(NN_TRY(unvalidatedConvertHelper(aidlNativeHandle))); } GeneralResult convert( @@ -508,13 +605,11 @@ nn::GeneralResult>> validatedConvert( return halObject; } -} // namespace - -nn::GeneralResult unvalidatedConvert(const nn::SharedHandle& sharedHandle) { +nn::GeneralResult unvalidatedConvert(const nn::Handle& handle) { common::NativeHandle aidlNativeHandle; - aidlNativeHandle.fds.reserve(sharedHandle->fds.size()); - for (const auto& fd : sharedHandle->fds) { - int dupFd = dup(fd.get()); + aidlNativeHandle.fds.reserve(handle.fds.size()); + for (const auto& fd : handle.fds) { + const int dupFd = dup(fd.get()); if (dupFd == -1) { // TODO(b/120417090): is ANEURALNETWORKS_UNEXPECTED_NULL the correct error to return // here? @@ -522,17 +617,69 @@ nn::GeneralResult unvalidatedConvert(const nn::SharedHandl } aidlNativeHandle.fds.emplace_back(dupFd); } - aidlNativeHandle.ints = sharedHandle->ints; + aidlNativeHandle.ints = handle.ints; return aidlNativeHandle; } +static nn::GeneralResult aidlHandleFromNativeHandle( + const native_handle_t& handle) { + common::NativeHandle aidlNativeHandle; + + aidlNativeHandle.fds.reserve(handle.numFds); + for (int i = 0; i < handle.numFds; ++i) { + const int dupFd = dup(handle.data[i]); + if (dupFd == -1) { + return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd"; + } + aidlNativeHandle.fds.emplace_back(dupFd); + } + + aidlNativeHandle.ints = std::vector(&handle.data[handle.numFds], + &handle.data[handle.numFds + handle.numInts]); + + return aidlNativeHandle; +} + +} // namespace + +nn::GeneralResult unvalidatedConvert(const nn::SharedHandle& sharedHandle) { + CHECK(sharedHandle != nullptr); + return unvalidatedConvert(*sharedHandle); +} + nn::GeneralResult unvalidatedConvert(const nn::SharedMemory& memory) { CHECK(memory != nullptr); if (memory->size > std::numeric_limits::max()) { return NN_ERROR() << "Memory size doesn't fit into int64_t."; } + if (const auto* handle = std::get_if(&memory->handle)) { + return Memory{ + .handle = NN_TRY(unvalidatedConvert(*handle)), + .size = static_cast(memory->size), + .name = memory->name, + }; + } + + const auto* ahwb = std::get(memory->handle).get(); + AHardwareBuffer_Desc bufferDesc; + AHardwareBuffer_describe(ahwb, &bufferDesc); + + if (bufferDesc.format == AHARDWAREBUFFER_FORMAT_BLOB) { + CHECK_EQ(memory->size, bufferDesc.width); + CHECK_EQ(memory->name, "hardware_buffer_blob"); + } else { + CHECK_EQ(memory->size, 0u); + CHECK_EQ(memory->name, "hardware_buffer"); + } + + const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(ahwb); + if (nativeHandle == nullptr) { + return NN_ERROR() << "unvalidatedConvert failed because AHardwareBuffer_getNativeHandle " + "returned nullptr"; + } + return Memory{ - .handle = NN_TRY(unvalidatedConvert(memory->handle)), + .handle = NN_TRY(aidlHandleFromNativeHandle(*nativeHandle)), .size = static_cast(memory->size), .name = memory->name, }; diff --git a/neuralnetworks/aidl/vts/functional/Utils.cpp b/neuralnetworks/aidl/vts/functional/Utils.cpp index 14a496a303..3c7f5f797d 100644 --- a/neuralnetworks/aidl/vts/functional/Utils.cpp +++ b/neuralnetworks/aidl/vts/functional/Utils.cpp @@ -135,7 +135,8 @@ void TestBlobAHWB::initialize(uint32_t size) { ASSERT_EQ(AHardwareBuffer_allocate(&desc, &mAhwb), 0); ASSERT_NE(mAhwb, nullptr); - const auto sharedMemory = nn::createSharedMemoryFromAHWB(*mAhwb).value(); + const auto sharedMemory = + nn::createSharedMemoryFromAHWB(mAhwb, /*takeOwnership=*/false).value(); mMapping = nn::map(sharedMemory).value(); mPtr = static_cast(std::get(mMapping.pointer)); CHECK_NE(mPtr, nullptr); diff --git a/neuralnetworks/utils/common/Android.bp b/neuralnetworks/utils/common/Android.bp index 6c491ae7ae..50295f1aad 100644 --- a/neuralnetworks/utils/common/Android.bp +++ b/neuralnetworks/utils/common/Android.bp @@ -22,10 +22,12 @@ cc_library_static { export_include_dirs: ["include"], cflags: ["-Wthread-safety"], static_libs: [ + "libarect", "neuralnetworks_types", ], shared_libs: [ "libhidlbase", + "libnativewindow", ], } diff --git a/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h b/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h index b13785dcd9..547f203d6d 100644 --- a/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h +++ b/neuralnetworks/utils/common/include/nnapi/hal/CommonUtils.h @@ -74,10 +74,12 @@ nn::GeneralResult unflushDataFromSharedToPointer( std::vector countNumberOfConsumers(size_t numberOfOperands, const std::vector& operations); +nn::GeneralResult createHidlMemoryFromSharedMemory(const nn::SharedMemory& memory); nn::GeneralResult createSharedMemoryFromHidlMemory(const hidl_memory& memory); -nn::GeneralResult hidlHandleFromSharedHandle(const nn::SharedHandle& handle); -nn::GeneralResult sharedHandleFromNativeHandle(const native_handle_t* handle); +nn::GeneralResult hidlHandleFromSharedHandle(const nn::Handle& handle); +nn::GeneralResult sharedHandleFromNativeHandle(const native_handle_t* handle); + nn::GeneralResult> convertSyncFences( const std::vector& fences); diff --git a/neuralnetworks/utils/common/src/CommonUtils.cpp b/neuralnetworks/utils/common/src/CommonUtils.cpp index 90215630c9..7a5035f6fc 100644 --- a/neuralnetworks/utils/common/src/CommonUtils.cpp +++ b/neuralnetworks/utils/common/src/CommonUtils.cpp @@ -20,11 +20,14 @@ #include #include +#include +#include #include #include #include #include #include +#include #include #include @@ -248,44 +251,128 @@ std::vector countNumberOfConsumers(size_t numberOfOperands, return nn::countNumberOfConsumers(numberOfOperands, operations); } -nn::GeneralResult hidlHandleFromSharedHandle(const nn::SharedHandle& handle) { - if (handle == nullptr) { - return {}; +nn::GeneralResult createHidlMemoryFromSharedMemory(const nn::SharedMemory& memory) { + if (memory == nullptr) { + return NN_ERROR() << "Memory must be non-empty"; + } + if (const auto* handle = std::get_if(&memory->handle)) { + return hidl_memory(memory->name, NN_TRY(hidlHandleFromSharedHandle(*handle)), memory->size); } + const auto* ahwb = std::get(memory->handle).get(); + AHardwareBuffer_Desc bufferDesc; + AHardwareBuffer_describe(ahwb, &bufferDesc); + + if (bufferDesc.format == AHARDWAREBUFFER_FORMAT_BLOB) { + CHECK_EQ(memory->size, bufferDesc.width); + CHECK_EQ(memory->name, "hardware_buffer_blob"); + } else { + CHECK_EQ(memory->size, 0u); + CHECK_EQ(memory->name, "hardware_buffer"); + } + + const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(ahwb); + const hidl_handle hidlHandle(nativeHandle); + hidl_handle handle(hidlHandle); + + return hidl_memory(memory->name, std::move(handle), memory->size); +} + +static uint32_t roundUpToMultiple(uint32_t value, uint32_t multiple) { + return (value + multiple - 1) / multiple * multiple; +} + +nn::GeneralResult createSharedMemoryFromHidlMemory(const hidl_memory& memory) { + CHECK_LE(memory.size(), std::numeric_limits::max()); + + if (memory.name() != "hardware_buffer_blob") { + return std::make_shared(nn::Memory{ + .handle = NN_TRY(sharedHandleFromNativeHandle(memory.handle())), + .size = static_cast(memory.size()), + .name = memory.name(), + }); + } + + const auto size = memory.size(); + const auto format = AHARDWAREBUFFER_FORMAT_BLOB; + const auto usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN | AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN; + const uint32_t width = size; + const uint32_t height = 1; // height is always 1 for BLOB mode AHardwareBuffer. + const uint32_t layers = 1; // layers is always 1 for BLOB mode AHardwareBuffer. + + // AHardwareBuffer_createFromHandle() might fail because an allocator + // expects a specific stride value. In that case, we try to guess it by + // aligning the width to small powers of 2. + // TODO(b/174120849): Avoid stride assumptions. + AHardwareBuffer* hardwareBuffer = nullptr; + status_t status = UNKNOWN_ERROR; + for (uint32_t alignment : {1, 4, 32, 64, 128, 2, 8, 16}) { + const uint32_t stride = roundUpToMultiple(width, alignment); + AHardwareBuffer_Desc desc{ + .width = width, + .height = height, + .layers = layers, + .format = format, + .usage = usage, + .stride = stride, + }; + status = AHardwareBuffer_createFromHandle(&desc, memory.handle(), + AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, + &hardwareBuffer); + if (status == NO_ERROR) { + break; + } + } + if (status != NO_ERROR) { + return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) + << "Can't create AHardwareBuffer from handle. Error: " << status; + } + + return std::make_shared(nn::Memory{ + .handle = nn::HardwareBufferHandle(hardwareBuffer, /*takeOwnership=*/true), + .size = static_cast(memory.size()), + .name = memory.name(), + }); +} + +nn::GeneralResult hidlHandleFromSharedHandle(const nn::Handle& handle) { std::vector fds; - fds.reserve(handle->fds.size()); - for (const auto& fd : handle->fds) { - int dupFd = dup(fd); + fds.reserve(handle.fds.size()); + for (const auto& fd : handle.fds) { + const int dupFd = dup(fd); if (dupFd == -1) { return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd"; } fds.emplace_back(dupFd); } - native_handle_t* nativeHandle = native_handle_create(handle->fds.size(), handle->ints.size()); + constexpr size_t kIntMax = std::numeric_limits::max(); + CHECK_LE(handle.fds.size(), kIntMax); + CHECK_LE(handle.ints.size(), kIntMax); + native_handle_t* nativeHandle = native_handle_create(static_cast(handle.fds.size()), + static_cast(handle.ints.size())); if (nativeHandle == nullptr) { return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to create native_handle"; } for (size_t i = 0; i < fds.size(); ++i) { nativeHandle->data[i] = fds[i].release(); } - std::copy(handle->ints.begin(), handle->ints.end(), &nativeHandle->data[nativeHandle->numFds]); + std::copy(handle.ints.begin(), handle.ints.end(), &nativeHandle->data[nativeHandle->numFds]); hidl_handle hidlHandle; hidlHandle.setTo(nativeHandle, /*shouldOwn=*/true); return hidlHandle; } -nn::GeneralResult sharedHandleFromNativeHandle(const native_handle_t* handle) { +nn::GeneralResult sharedHandleFromNativeHandle(const native_handle_t* handle) { if (handle == nullptr) { - return nullptr; + return NN_ERROR() << "sharedHandleFromNativeHandle failed because handle is nullptr"; } std::vector fds; fds.reserve(handle->numFds); for (int i = 0; i < handle->numFds; ++i) { - int dupFd = dup(handle->data[i]); + const int dupFd = dup(handle->data[i]); if (dupFd == -1) { return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Failed to dup the fd"; } @@ -295,18 +382,18 @@ nn::GeneralResult sharedHandleFromNativeHandle(const native_ha std::vector ints(&handle->data[handle->numFds], &handle->data[handle->numFds + handle->numInts]); - return std::make_shared(nn::Handle{ - .fds = std::move(fds), - .ints = std::move(ints), - }); + return nn::Handle{.fds = std::move(fds), .ints = std::move(ints)}; } nn::GeneralResult> convertSyncFences( const std::vector& syncFences) { hidl_vec handles(syncFences.size()); for (size_t i = 0; i < syncFences.size(); ++i) { - handles[i] = - NN_TRY(hal::utils::hidlHandleFromSharedHandle(syncFences[i].getSharedHandle())); + const auto& handle = syncFences[i].getSharedHandle(); + if (handle == nullptr) { + return NN_ERROR() << "convertSyncFences failed because sync fence is empty"; + } + handles[i] = NN_TRY(hidlHandleFromSharedHandle(*handle)); } return handles; }