From 6547b2ac9c963d92fa80e822963240fe07a7da9f Mon Sep 17 00:00:00 2001 From: Michael Butler Date: Sun, 22 Nov 2020 19:36:30 -0800 Subject: [PATCH] Validate during NN conversions by default -- hal This change renames all `convert` functions to `unvalidatedConvert`. This change also introduces new `convert` functions that act only on the types that appear in the NN HIDL methods directly. These new `convert` functions perform validation. Specifically, if either the source or destination value is invalid, then the conversion fails. Bug: 160667419 Test: mma Test: NeuralNetworksTest_static Change-Id: I492956ff60ad1466c67893993d28cdd6f3860708 Merged-In: I492956ff60ad1466c67893993d28cdd6f3860708 (cherry picked from commit 32acc0614402a35eed3407116ec359f4fdb60ecc) --- .../utils/include/nnapi/hal/1.0/Conversions.h | 61 ++- .../1.0/utils/include/nnapi/hal/1.0/Utils.h | 24 -- neuralnetworks/1.0/utils/src/Callbacks.cpp | 6 +- neuralnetworks/1.0/utils/src/Conversions.cpp | 222 ++++++---- neuralnetworks/1.0/utils/src/Device.cpp | 11 +- .../1.0/utils/src/PreparedModel.cpp | 3 +- .../utils/include/nnapi/hal/1.1/Conversions.h | 18 +- .../1.1/utils/include/nnapi/hal/1.1/Utils.h | 23 - neuralnetworks/1.1/utils/src/Conversions.cpp | 157 +++++-- neuralnetworks/1.1/utils/src/Device.cpp | 11 +- .../utils/include/nnapi/hal/1.2/Conversions.h | 78 ++-- .../1.2/utils/include/nnapi/hal/1.2/Utils.h | 23 - neuralnetworks/1.2/utils/src/Callbacks.cpp | 15 +- neuralnetworks/1.2/utils/src/Conversions.cpp | 302 ++++++++----- neuralnetworks/1.2/utils/src/Device.cpp | 26 +- .../1.2/utils/src/PreparedModel.cpp | 9 +- .../utils/include/nnapi/hal/1.3/Conversions.h | 69 ++- .../1.3/utils/include/nnapi/hal/1.3/Utils.h | 23 - neuralnetworks/1.3/utils/src/Buffer.cpp | 10 +- neuralnetworks/1.3/utils/src/Callbacks.cpp | 21 +- neuralnetworks/1.3/utils/src/Conversions.cpp | 400 ++++++++++++------ neuralnetworks/1.3/utils/src/Device.cpp | 17 +- .../1.3/utils/src/PreparedModel.cpp | 24 +- neuralnetworks/utils/README.md | 50 +++ 24 files changed, 994 insertions(+), 609 deletions(-) create mode 100644 neuralnetworks/utils/README.md 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 fb77cb2475..d3d933b22c 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 @@ -24,20 +24,28 @@ namespace android::nn { -GeneralResult convert(const hal::V1_0::OperandType& operandType); -GeneralResult convert(const hal::V1_0::OperationType& operationType); -GeneralResult convert(const hal::V1_0::OperandLifeTime& lifetime); -GeneralResult convert(const hal::V1_0::DeviceStatus& deviceStatus); -GeneralResult convert( +GeneralResult unvalidatedConvert(const hal::V1_0::OperandType& operandType); +GeneralResult unvalidatedConvert(const hal::V1_0::OperationType& operationType); +GeneralResult unvalidatedConvert(const hal::V1_0::OperandLifeTime& lifetime); +GeneralResult unvalidatedConvert(const hal::V1_0::DeviceStatus& deviceStatus); +GeneralResult unvalidatedConvert( const hal::V1_0::PerformanceInfo& performanceInfo); +GeneralResult unvalidatedConvert(const hal::V1_0::Capabilities& capabilities); +GeneralResult unvalidatedConvert(const hal::V1_0::DataLocation& location); +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 hal::V1_0::Model& model); +GeneralResult unvalidatedConvert( + const hal::V1_0::RequestArgument& requestArgument); +GeneralResult unvalidatedConvert(const hal::V1_0::Request& request); +GeneralResult unvalidatedConvert(const hal::V1_0::ErrorStatus& status); + +GeneralResult convert(const hal::V1_0::DeviceStatus& deviceStatus); GeneralResult convert(const hal::V1_0::Capabilities& capabilities); -GeneralResult convert(const hal::V1_0::DataLocation& location); -GeneralResult convert(const hal::V1_0::Operand& operand); -GeneralResult convert(const hal::V1_0::Operation& operation); -GeneralResult convert(const hardware::hidl_vec& operandValues); -GeneralResult convert(const hardware::hidl_memory& memory); GeneralResult convert(const hal::V1_0::Model& model); -GeneralResult convert(const hal::V1_0::RequestArgument& requestArgument); GeneralResult convert(const hal::V1_0::Request& request); GeneralResult convert(const hal::V1_0::ErrorStatus& status); @@ -45,21 +53,28 @@ GeneralResult convert(const hal::V1_0::ErrorStatus& status); namespace android::hardware::neuralnetworks::V1_0::utils { -nn::GeneralResult convert(const nn::OperandType& operandType); -nn::GeneralResult convert(const nn::OperationType& operationType); -nn::GeneralResult convert(const nn::Operand::LifeTime& lifetime); -nn::GeneralResult convert(const nn::DeviceStatus& deviceStatus); -nn::GeneralResult convert( +nn::GeneralResult unvalidatedConvert(const nn::OperandType& operandType); +nn::GeneralResult unvalidatedConvert(const nn::OperationType& operationType); +nn::GeneralResult unvalidatedConvert(const nn::Operand::LifeTime& lifetime); +nn::GeneralResult unvalidatedConvert(const nn::DeviceStatus& deviceStatus); +nn::GeneralResult unvalidatedConvert( const nn::Capabilities::PerformanceInfo& performanceInfo); +nn::GeneralResult unvalidatedConvert(const nn::Capabilities& capabilities); +nn::GeneralResult unvalidatedConvert(const nn::DataLocation& location); +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::Model& model); +nn::GeneralResult unvalidatedConvert(const nn::Request::Argument& requestArgument); +nn::GeneralResult unvalidatedConvert(const nn::Request::MemoryPool& memoryPool); +nn::GeneralResult unvalidatedConvert(const nn::Request& request); +nn::GeneralResult unvalidatedConvert(const nn::ErrorStatus& status); + +nn::GeneralResult convert(const nn::DeviceStatus& deviceStatus); nn::GeneralResult convert(const nn::Capabilities& capabilities); -nn::GeneralResult convert(const nn::DataLocation& location); -nn::GeneralResult convert(const nn::Operand& operand); -nn::GeneralResult convert(const nn::Operation& operation); -nn::GeneralResult> convert(const nn::Model::OperandValues& operandValues); -nn::GeneralResult convert(const nn::Memory& memory); nn::GeneralResult convert(const nn::Model& model); -nn::GeneralResult convert(const nn::Request::Argument& requestArgument); -nn::GeneralResult convert(const nn::Request::MemoryPool& memoryPool); nn::GeneralResult convert(const nn::Request& request); nn::GeneralResult convert(const nn::ErrorStatus& status); diff --git a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h index baa2b9523e..4cec545cf0 100644 --- a/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h +++ b/neuralnetworks/1.0/utils/include/nnapi/hal/1.0/Utils.h @@ -22,25 +22,16 @@ #include #include #include -#include #include -#include namespace android::hardware::neuralnetworks::V1_0::utils { -constexpr auto kVersion = nn::Version::ANDROID_OC_MR1; - template nn::Result validate(const Type& halObject) { const auto maybeCanonical = nn::convert(halObject); if (!maybeCanonical.has_value()) { return nn::error() << maybeCanonical.error().message; } - const auto version = NN_TRY(nn::validate(maybeCanonical.value())); - if (version > utils::kVersion) { - return NN_ERROR() << "Insufficient version: " << version << " vs required " - << utils::kVersion; - } return {}; } @@ -53,21 +44,6 @@ bool valid(const Type& halObject) { return result.has_value(); } -template -decltype(nn::convert(std::declval())) validatedConvertToCanonical(const Type& halObject) { - auto canonical = NN_TRY(nn::convert(halObject)); - const auto maybeVersion = nn::validate(canonical); - if (!maybeVersion.has_value()) { - return nn::error() << maybeVersion.error(); - } - const auto version = maybeVersion.value(); - if (version > utils::kVersion) { - return NN_ERROR() << "Insufficient version: " << version << " vs required " - << utils::kVersion; - } - return canonical; -} - } // namespace android::hardware::neuralnetworks::V1_0::utils #endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_0_UTILS_H diff --git a/neuralnetworks/1.0/utils/src/Callbacks.cpp b/neuralnetworks/1.0/utils/src/Callbacks.cpp index f286bcc50e..b1259c3c56 100644 --- a/neuralnetworks/1.0/utils/src/Callbacks.cpp +++ b/neuralnetworks/1.0/utils/src/Callbacks.cpp @@ -45,8 +45,7 @@ nn::GeneralResult convertPreparedModel( Return PreparedModelCallback::notify(ErrorStatus status, const sp& preparedModel) { if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status)); } else if (preparedModel == nullptr) { notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) @@ -73,8 +72,7 @@ void PreparedModelCallback::notifyInternal(PreparedModelCallback::Data result) { Return ExecutionCallback::notify(ErrorStatus status) { if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status)); } else { notifyInternal({}); diff --git a/neuralnetworks/1.0/utils/src/Conversions.cpp b/neuralnetworks/1.0/utils/src/Conversions.cpp index 6cf907380e..fde7346470 100644 --- a/neuralnetworks/1.0/utils/src/Conversions.cpp +++ b/neuralnetworks/1.0/utils/src/Conversions.cpp @@ -22,7 +22,9 @@ #include #include #include +#include #include +#include #include #include @@ -40,6 +42,8 @@ constexpr std::underlying_type_t underlyingType(Type value) { return static_cast>(value); } +constexpr auto kVersion = android::nn::Version::ANDROID_OC_MR1; + } // namespace namespace android::nn { @@ -49,37 +53,53 @@ using hardware::hidl_memory; using hardware::hidl_vec; template -using ConvertOutput = std::decay_t()).value())>; +using unvalidatedConvertOutput = + std::decay_t()).value())>; template -GeneralResult>> convert(const hidl_vec& arguments) { - std::vector> canonical; +GeneralResult>> unvalidatedConvert( + const hidl_vec& arguments) { + std::vector> canonical; canonical.reserve(arguments.size()); for (const auto& argument : arguments) { - canonical.push_back(NN_TRY(nn::convert(argument))); + canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument))); + } + return canonical; +} + +template +decltype(nn::unvalidatedConvert(std::declval())) validatedConvert(const Type& halObject) { + auto canonical = NN_TRY(nn::unvalidatedConvert(halObject)); + const auto maybeVersion = validate(canonical); + if (!maybeVersion.has_value()) { + return error() << maybeVersion.error(); + } + const auto version = maybeVersion.value(); + if (version > kVersion) { + return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion; } return canonical; } } // anonymous namespace -GeneralResult convert(const hal::V1_0::OperandType& operandType) { +GeneralResult unvalidatedConvert(const hal::V1_0::OperandType& operandType) { return static_cast(operandType); } -GeneralResult convert(const hal::V1_0::OperationType& operationType) { +GeneralResult unvalidatedConvert(const hal::V1_0::OperationType& operationType) { return static_cast(operationType); } -GeneralResult convert(const hal::V1_0::OperandLifeTime& lifetime) { +GeneralResult unvalidatedConvert(const hal::V1_0::OperandLifeTime& lifetime) { return static_cast(lifetime); } -GeneralResult convert(const hal::V1_0::DeviceStatus& deviceStatus) { +GeneralResult unvalidatedConvert(const hal::V1_0::DeviceStatus& deviceStatus) { return static_cast(deviceStatus); } -GeneralResult convert( +GeneralResult unvalidatedConvert( const hal::V1_0::PerformanceInfo& performanceInfo) { return Capabilities::PerformanceInfo{ .execTime = performanceInfo.execTime, @@ -87,9 +107,10 @@ GeneralResult convert( }; } -GeneralResult convert(const hal::V1_0::Capabilities& capabilities) { - const auto quantized8Performance = NN_TRY(convert(capabilities.quantized8Performance)); - const auto float32Performance = NN_TRY(convert(capabilities.float32Performance)); +GeneralResult unvalidatedConvert(const hal::V1_0::Capabilities& capabilities) { + const auto quantized8Performance = + NN_TRY(unvalidatedConvert(capabilities.quantized8Performance)); + const auto float32Performance = NN_TRY(unvalidatedConvert(capabilities.float32Performance)); auto table = hal::utils::makeQuantized8PerformanceConsistentWithP(float32Performance, quantized8Performance); @@ -101,7 +122,7 @@ GeneralResult convert(const hal::V1_0::Capabilities& capabilities) }; } -GeneralResult convert(const hal::V1_0::DataLocation& location) { +GeneralResult unvalidatedConvert(const hal::V1_0::DataLocation& location) { return DataLocation{ .poolIndex = location.poolIndex, .offset = location.offset, @@ -109,35 +130,35 @@ GeneralResult convert(const hal::V1_0::DataLocation& location) { }; } -GeneralResult convert(const hal::V1_0::Operand& operand) { +GeneralResult unvalidatedConvert(const hal::V1_0::Operand& operand) { return Operand{ - .type = NN_TRY(convert(operand.type)), + .type = NN_TRY(unvalidatedConvert(operand.type)), .dimensions = operand.dimensions, .scale = operand.scale, .zeroPoint = operand.zeroPoint, - .lifetime = NN_TRY(convert(operand.lifetime)), - .location = NN_TRY(convert(operand.location)), + .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)), + .location = NN_TRY(unvalidatedConvert(operand.location)), }; } -GeneralResult convert(const hal::V1_0::Operation& operation) { +GeneralResult unvalidatedConvert(const hal::V1_0::Operation& operation) { return Operation{ - .type = NN_TRY(convert(operation.type)), + .type = NN_TRY(unvalidatedConvert(operation.type)), .inputs = operation.inputs, .outputs = operation.outputs, }; } -GeneralResult convert(const hidl_vec& operandValues) { +GeneralResult unvalidatedConvert(const hidl_vec& operandValues) { return Model::OperandValues(operandValues.data(), operandValues.size()); } -GeneralResult convert(const hidl_memory& memory) { +GeneralResult unvalidatedConvert(const hidl_memory& memory) { return createSharedMemoryFromHidlMemory(memory); } -GeneralResult convert(const hal::V1_0::Model& model) { - auto operations = NN_TRY(convert(model.operations)); +GeneralResult unvalidatedConvert(const hal::V1_0::Model& model) { + auto operations = NN_TRY(unvalidatedConvert(model.operations)); // Verify number of consumers. const auto numberOfConsumers = @@ -152,7 +173,7 @@ GeneralResult convert(const hal::V1_0::Model& model) { } auto main = Model::Subgraph{ - .operands = NN_TRY(convert(model.operands)), + .operands = NN_TRY(unvalidatedConvert(model.operands)), .operations = std::move(operations), .inputIndexes = model.inputIndexes, .outputIndexes = model.outputIndexes, @@ -160,35 +181,35 @@ GeneralResult convert(const hal::V1_0::Model& model) { return Model{ .main = std::move(main), - .operandValues = NN_TRY(convert(model.operandValues)), - .pools = NN_TRY(convert(model.pools)), + .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)), + .pools = NN_TRY(unvalidatedConvert(model.pools)), }; } -GeneralResult convert(const hal::V1_0::RequestArgument& argument) { +GeneralResult unvalidatedConvert(const hal::V1_0::RequestArgument& argument) { const auto lifetime = argument.hasNoValue ? Request::Argument::LifeTime::NO_VALUE : Request::Argument::LifeTime::POOL; return Request::Argument{ .lifetime = lifetime, - .location = NN_TRY(convert(argument.location)), + .location = NN_TRY(unvalidatedConvert(argument.location)), .dimensions = argument.dimensions, }; } -GeneralResult convert(const hal::V1_0::Request& request) { - auto memories = NN_TRY(convert(request.pools)); +GeneralResult unvalidatedConvert(const hal::V1_0::Request& request) { + auto memories = NN_TRY(unvalidatedConvert(request.pools)); std::vector pools; pools.reserve(memories.size()); std::move(memories.begin(), memories.end(), std::back_inserter(pools)); return Request{ - .inputs = NN_TRY(convert(request.inputs)), - .outputs = NN_TRY(convert(request.outputs)), + .inputs = NN_TRY(unvalidatedConvert(request.inputs)), + .outputs = NN_TRY(unvalidatedConvert(request.outputs)), .pools = std::move(pools), }; } -GeneralResult convert(const hal::V1_0::ErrorStatus& status) { +GeneralResult unvalidatedConvert(const hal::V1_0::ErrorStatus& status) { switch (status) { case hal::V1_0::ErrorStatus::NONE: case hal::V1_0::ErrorStatus::DEVICE_UNAVAILABLE: @@ -201,46 +222,81 @@ GeneralResult convert(const hal::V1_0::ErrorStatus& status) { << "Invalid ErrorStatus " << underlyingType(status); } +GeneralResult convert(const hal::V1_0::DeviceStatus& deviceStatus) { + return validatedConvert(deviceStatus); +} + +GeneralResult convert(const hal::V1_0::Capabilities& capabilities) { + return validatedConvert(capabilities); +} + +GeneralResult convert(const hal::V1_0::Model& model) { + return validatedConvert(model); +} + +GeneralResult convert(const hal::V1_0::Request& request) { + return validatedConvert(request); +} + +GeneralResult convert(const hal::V1_0::ErrorStatus& status) { + return validatedConvert(status); +} + } // namespace android::nn namespace android::hardware::neuralnetworks::V1_0::utils { namespace { template -using ConvertOutput = std::decay_t()).value())>; +using unvalidatedConvertOutput = + std::decay_t()).value())>; template -nn::GeneralResult>> convert(const std::vector& arguments) { - hidl_vec> halObject(arguments.size()); +nn::GeneralResult>> unvalidatedConvert( + const std::vector& arguments) { + hidl_vec> halObject(arguments.size()); for (size_t i = 0; i < arguments.size(); ++i) { - halObject[i] = NN_TRY(utils::convert(arguments[i])); + halObject[i] = NN_TRY(utils::unvalidatedConvert(arguments[i])); } return halObject; } +template +decltype(utils::unvalidatedConvert(std::declval())) validatedConvert(const Type& canonical) { + const auto maybeVersion = nn::validate(canonical); + if (!maybeVersion.has_value()) { + return nn::error() << maybeVersion.error(); + } + const auto version = maybeVersion.value(); + if (version > kVersion) { + return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion; + } + return utils::unvalidatedConvert(canonical); +} + } // anonymous namespace -nn::GeneralResult convert(const nn::OperandType& operandType) { +nn::GeneralResult unvalidatedConvert(const nn::OperandType& operandType) { return static_cast(operandType); } -nn::GeneralResult convert(const nn::OperationType& operationType) { +nn::GeneralResult unvalidatedConvert(const nn::OperationType& operationType) { return static_cast(operationType); } -nn::GeneralResult convert(const nn::Operand::LifeTime& lifetime) { +nn::GeneralResult unvalidatedConvert(const nn::Operand::LifeTime& lifetime) { if (lifetime == nn::Operand::LifeTime::POINTER) { return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) - << "Model cannot be converted because it contains pointer-based memory"; + << "Model cannot be unvalidatedConverted because it contains pointer-based memory"; } return static_cast(lifetime); } -nn::GeneralResult convert(const nn::DeviceStatus& deviceStatus) { +nn::GeneralResult unvalidatedConvert(const nn::DeviceStatus& deviceStatus) { return static_cast(deviceStatus); } -nn::GeneralResult convert( +nn::GeneralResult unvalidatedConvert( const nn::Capabilities::PerformanceInfo& performanceInfo) { return PerformanceInfo{ .execTime = performanceInfo.execTime, @@ -248,16 +304,16 @@ nn::GeneralResult convert( }; } -nn::GeneralResult convert(const nn::Capabilities& capabilities) { +nn::GeneralResult unvalidatedConvert(const nn::Capabilities& capabilities) { return Capabilities{ - .float32Performance = NN_TRY(convert( + .float32Performance = NN_TRY(unvalidatedConvert( capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_FLOAT32))), - .quantized8Performance = NN_TRY(convert( + .quantized8Performance = NN_TRY(unvalidatedConvert( capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_QUANT8_ASYMM))), }; } -nn::GeneralResult convert(const nn::DataLocation& location) { +nn::GeneralResult unvalidatedConvert(const nn::DataLocation& location) { return DataLocation{ .poolIndex = location.poolIndex, .offset = location.offset, @@ -265,42 +321,43 @@ nn::GeneralResult convert(const nn::DataLocation& location) { }; } -nn::GeneralResult convert(const nn::Operand& operand) { +nn::GeneralResult unvalidatedConvert(const nn::Operand& operand) { return Operand{ - .type = NN_TRY(convert(operand.type)), + .type = NN_TRY(unvalidatedConvert(operand.type)), .dimensions = operand.dimensions, .numberOfConsumers = 0, .scale = operand.scale, .zeroPoint = operand.zeroPoint, - .lifetime = NN_TRY(convert(operand.lifetime)), - .location = NN_TRY(convert(operand.location)), + .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)), + .location = NN_TRY(unvalidatedConvert(operand.location)), }; } -nn::GeneralResult convert(const nn::Operation& operation) { +nn::GeneralResult unvalidatedConvert(const nn::Operation& operation) { return Operation{ - .type = NN_TRY(convert(operation.type)), + .type = NN_TRY(unvalidatedConvert(operation.type)), .inputs = operation.inputs, .outputs = operation.outputs, }; } -nn::GeneralResult> convert(const nn::Model::OperandValues& operandValues) { +nn::GeneralResult> unvalidatedConvert( + const nn::Model::OperandValues& operandValues) { return hidl_vec(operandValues.data(), operandValues.data() + operandValues.size()); } -nn::GeneralResult convert(const nn::Memory& memory) { +nn::GeneralResult unvalidatedConvert(const nn::Memory& memory) { return hidl_memory(memory.name, NN_TRY(hal::utils::hidlHandleFromSharedHandle(memory.handle)), memory.size); } -nn::GeneralResult convert(const nn::Model& model) { +nn::GeneralResult unvalidatedConvert(const nn::Model& model) { if (!hal::utils::hasNoPointerData(model)) { return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) - << "Mdoel cannot be converted because it contains pointer-based memory"; + << "Mdoel cannot be unvalidatedConverted because it contains pointer-based memory"; } - auto operands = NN_TRY(convert(model.main.operands)); + auto operands = NN_TRY(unvalidatedConvert(model.main.operands)); // Update number of consumers. const auto numberOfConsumers = @@ -312,45 +369,46 @@ nn::GeneralResult convert(const nn::Model& model) { return Model{ .operands = std::move(operands), - .operations = NN_TRY(convert(model.main.operations)), + .operations = NN_TRY(unvalidatedConvert(model.main.operations)), .inputIndexes = model.main.inputIndexes, .outputIndexes = model.main.outputIndexes, - .operandValues = NN_TRY(convert(model.operandValues)), - .pools = NN_TRY(convert(model.pools)), + .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)), + .pools = NN_TRY(unvalidatedConvert(model.pools)), }; } -nn::GeneralResult convert(const nn::Request::Argument& requestArgument) { +nn::GeneralResult unvalidatedConvert( + const nn::Request::Argument& requestArgument) { if (requestArgument.lifetime == nn::Request::Argument::LifeTime::POINTER) { return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) - << "Request cannot be converted because it contains pointer-based memory"; + << "Request cannot be unvalidatedConverted because it contains pointer-based memory"; } const bool hasNoValue = requestArgument.lifetime == nn::Request::Argument::LifeTime::NO_VALUE; return RequestArgument{ .hasNoValue = hasNoValue, - .location = NN_TRY(convert(requestArgument.location)), + .location = NN_TRY(unvalidatedConvert(requestArgument.location)), .dimensions = requestArgument.dimensions, }; } -nn::GeneralResult convert(const nn::Request::MemoryPool& memoryPool) { - return convert(std::get(memoryPool)); +nn::GeneralResult unvalidatedConvert(const nn::Request::MemoryPool& memoryPool) { + return unvalidatedConvert(std::get(memoryPool)); } -nn::GeneralResult convert(const nn::Request& request) { +nn::GeneralResult unvalidatedConvert(const nn::Request& request) { if (!hal::utils::hasNoPointerData(request)) { return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) - << "Request cannot be converted because it contains pointer-based memory"; + << "Request cannot be unvalidatedConverted because it contains pointer-based memory"; } return Request{ - .inputs = NN_TRY(convert(request.inputs)), - .outputs = NN_TRY(convert(request.outputs)), - .pools = NN_TRY(convert(request.pools)), + .inputs = NN_TRY(unvalidatedConvert(request.inputs)), + .outputs = NN_TRY(unvalidatedConvert(request.outputs)), + .pools = NN_TRY(unvalidatedConvert(request.pools)), }; } -nn::GeneralResult convert(const nn::ErrorStatus& status) { +nn::GeneralResult unvalidatedConvert(const nn::ErrorStatus& status) { switch (status) { case nn::ErrorStatus::NONE: case nn::ErrorStatus::DEVICE_UNAVAILABLE: @@ -363,4 +421,24 @@ nn::GeneralResult convert(const nn::ErrorStatus& status) { } } +nn::GeneralResult convert(const nn::DeviceStatus& deviceStatus) { + return validatedConvert(deviceStatus); +} + +nn::GeneralResult convert(const nn::Capabilities& capabilities) { + return validatedConvert(capabilities); +} + +nn::GeneralResult convert(const nn::Model& model) { + return validatedConvert(model); +} + +nn::GeneralResult convert(const nn::Request& request) { + return validatedConvert(request); +} + +nn::GeneralResult convert(const nn::ErrorStatus& status) { + return validatedConvert(status); +} + } // namespace android::hardware::neuralnetworks::V1_0::utils diff --git a/neuralnetworks/1.0/utils/src/Device.cpp b/neuralnetworks/1.0/utils/src/Device.cpp index 671416b9eb..ab3f5afb23 100644 --- a/neuralnetworks/1.0/utils/src/Device.cpp +++ b/neuralnetworks/1.0/utils/src/Device.cpp @@ -48,11 +48,10 @@ nn::GeneralResult initCapabilities(V1_0::IDevice* device) { << "uninitialized"; const auto cb = [&result](ErrorStatus status, const Capabilities& capabilities) { if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "getCapabilities failed with " << toString(status); } else { - result = validatedConvertToCanonical(capabilities); + result = nn::convert(capabilities); } }; @@ -135,8 +134,7 @@ nn::GeneralResult> Device::getSupportedOperations(const nn::Mo << "uninitialized"; auto cb = [&result, &model](ErrorStatus status, const hidl_vec& supportedOperations) { if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "getSupportedOperations failed with " << toString(status); } else if (supportedOperations.size() != model.main.operations.size()) { @@ -172,8 +170,7 @@ nn::GeneralResult Device::prepareModel( const auto ret = kDevice->prepareModel(hidlModel, cb); const auto status = NN_TRY(hal::utils::handleTransportError(ret)); if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); return NN_ERROR(canonical) << "prepareModel failed with " << toString(status); } diff --git a/neuralnetworks/1.0/utils/src/PreparedModel.cpp b/neuralnetworks/1.0/utils/src/PreparedModel.cpp index 11ccbe3221..80f885a64e 100644 --- a/neuralnetworks/1.0/utils/src/PreparedModel.cpp +++ b/neuralnetworks/1.0/utils/src/PreparedModel.cpp @@ -70,8 +70,7 @@ nn::ExecutionResult, nn::Timing>> Prepare const auto status = NN_TRY(hal::utils::makeExecutionFailure(hal::utils::handleTransportError(ret))); if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); return NN_ERROR(canonical) << "execute failed with " << toString(status); } diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Conversions.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Conversions.h index 16ddd53496..f64646257f 100644 --- a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Conversions.h +++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Conversions.h @@ -24,9 +24,14 @@ namespace android::nn { -GeneralResult convert(const hal::V1_1::OperationType& operationType); +GeneralResult unvalidatedConvert(const hal::V1_1::OperationType& operationType); +GeneralResult unvalidatedConvert(const hal::V1_1::Capabilities& capabilities); +GeneralResult unvalidatedConvert(const hal::V1_1::Operation& operation); +GeneralResult unvalidatedConvert(const hal::V1_1::Model& model); +GeneralResult unvalidatedConvert( + const hal::V1_1::ExecutionPreference& executionPreference); + GeneralResult convert(const hal::V1_1::Capabilities& capabilities); -GeneralResult convert(const hal::V1_1::Operation& operation); GeneralResult convert(const hal::V1_1::Model& model); GeneralResult convert( const hal::V1_1::ExecutionPreference& executionPreference); @@ -35,9 +40,14 @@ GeneralResult convert( namespace android::hardware::neuralnetworks::V1_1::utils { -nn::GeneralResult convert(const nn::OperationType& operationType); +nn::GeneralResult unvalidatedConvert(const nn::OperationType& operationType); +nn::GeneralResult unvalidatedConvert(const nn::Capabilities& capabilities); +nn::GeneralResult unvalidatedConvert(const nn::Operation& operation); +nn::GeneralResult unvalidatedConvert(const nn::Model& model); +nn::GeneralResult unvalidatedConvert( + const nn::ExecutionPreference& executionPreference); + nn::GeneralResult convert(const nn::Capabilities& capabilities); -nn::GeneralResult convert(const nn::Operation& operation); nn::GeneralResult convert(const nn::Model& model); nn::GeneralResult convert(const nn::ExecutionPreference& executionPreference); diff --git a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h index 0fee628eb6..052d88e922 100644 --- a/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h +++ b/neuralnetworks/1.1/utils/include/nnapi/hal/1.1/Utils.h @@ -22,15 +22,12 @@ #include #include #include -#include #include -#include #include namespace android::hardware::neuralnetworks::V1_1::utils { constexpr auto kDefaultExecutionPreference = ExecutionPreference::FAST_SINGLE_ANSWER; -constexpr auto kVersion = nn::Version::ANDROID_P; template nn::Result validate(const Type& halObject) { @@ -38,11 +35,6 @@ nn::Result validate(const Type& halObject) { if (!maybeCanonical.has_value()) { return nn::error() << maybeCanonical.error().message; } - const auto version = NN_TRY(nn::validate(maybeCanonical.value())); - if (version > utils::kVersion) { - return NN_ERROR() << "Insufficient version: " << version << " vs required " - << utils::kVersion; - } return {}; } @@ -55,21 +47,6 @@ bool valid(const Type& halObject) { return result.has_value(); } -template -decltype(nn::convert(std::declval())) validatedConvertToCanonical(const Type& halObject) { - auto canonical = NN_TRY(nn::convert(halObject)); - const auto maybeVersion = nn::validate(canonical); - if (!maybeVersion.has_value()) { - return nn::error() << maybeVersion.error(); - } - const auto version = maybeVersion.value(); - if (version > utils::kVersion) { - return NN_ERROR() << "Insufficient version: " << version << " vs required " - << utils::kVersion; - } - return canonical; -} - } // namespace android::hardware::neuralnetworks::V1_1::utils #endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_1_UTILS_H diff --git a/neuralnetworks/1.1/utils/src/Conversions.cpp b/neuralnetworks/1.1/utils/src/Conversions.cpp index ffe0752c11..359f68ad4d 100644 --- a/neuralnetworks/1.1/utils/src/Conversions.cpp +++ b/neuralnetworks/1.1/utils/src/Conversions.cpp @@ -23,7 +23,9 @@ #include #include #include +#include #include +#include #include #include @@ -33,35 +35,58 @@ #include #include +namespace { + +constexpr auto kVersion = android::nn::Version::ANDROID_P; + +} // namespace + namespace android::nn { namespace { using hardware::hidl_vec; template -using convertOutput = std::decay_t()).value())>; +using unvalidatedConvertOutput = + std::decay_t()).value())>; template -GeneralResult>> convert(const hidl_vec& arguments) { - std::vector> canonical; +GeneralResult>> unvalidatedConvert( + const hidl_vec& arguments) { + std::vector> canonical; canonical.reserve(arguments.size()); for (const auto& argument : arguments) { - canonical.push_back(NN_TRY(nn::convert(argument))); + canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument))); + } + return canonical; +} + +template +decltype(nn::unvalidatedConvert(std::declval())) validatedConvert(const Type& halObject) { + auto canonical = NN_TRY(nn::unvalidatedConvert(halObject)); + const auto maybeVersion = validate(canonical); + if (!maybeVersion.has_value()) { + return error() << maybeVersion.error(); + } + const auto version = maybeVersion.value(); + if (version > kVersion) { + return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion; } return canonical; } } // anonymous namespace -GeneralResult convert(const hal::V1_1::OperationType& operationType) { +GeneralResult unvalidatedConvert(const hal::V1_1::OperationType& operationType) { return static_cast(operationType); } -GeneralResult convert(const hal::V1_1::Capabilities& capabilities) { - const auto quantized8Performance = NN_TRY(convert(capabilities.quantized8Performance)); - const auto float32Performance = NN_TRY(convert(capabilities.float32Performance)); +GeneralResult unvalidatedConvert(const hal::V1_1::Capabilities& capabilities) { + const auto quantized8Performance = + NN_TRY(unvalidatedConvert(capabilities.quantized8Performance)); + const auto float32Performance = NN_TRY(unvalidatedConvert(capabilities.float32Performance)); const auto relaxedFloat32toFloat16Performance = - NN_TRY(convert(capabilities.relaxedFloat32toFloat16Performance)); + NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16Performance)); auto table = hal::utils::makeQuantized8PerformanceConsistentWithP(float32Performance, quantized8Performance); @@ -73,16 +98,16 @@ GeneralResult convert(const hal::V1_1::Capabilities& capabilities) }; } -GeneralResult convert(const hal::V1_1::Operation& operation) { +GeneralResult unvalidatedConvert(const hal::V1_1::Operation& operation) { return Operation{ - .type = NN_TRY(convert(operation.type)), + .type = NN_TRY(unvalidatedConvert(operation.type)), .inputs = operation.inputs, .outputs = operation.outputs, }; } -GeneralResult convert(const hal::V1_1::Model& model) { - auto operations = NN_TRY(convert(model.operations)); +GeneralResult unvalidatedConvert(const hal::V1_1::Model& model) { + auto operations = NN_TRY(unvalidatedConvert(model.operations)); // Verify number of consumers. const auto numberOfConsumers = @@ -97,7 +122,7 @@ GeneralResult convert(const hal::V1_1::Model& model) { } auto main = Model::Subgraph{ - .operands = NN_TRY(convert(model.operands)), + .operands = NN_TRY(unvalidatedConvert(model.operands)), .operations = std::move(operations), .inputIndexes = model.inputIndexes, .outputIndexes = model.outputIndexes, @@ -105,85 +130,114 @@ GeneralResult convert(const hal::V1_1::Model& model) { return Model{ .main = std::move(main), - .operandValues = NN_TRY(convert(model.operandValues)), - .pools = NN_TRY(convert(model.pools)), + .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)), + .pools = NN_TRY(unvalidatedConvert(model.pools)), .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16, }; } -GeneralResult convert( +GeneralResult unvalidatedConvert( const hal::V1_1::ExecutionPreference& executionPreference) { return static_cast(executionPreference); } +GeneralResult convert(const hal::V1_1::Capabilities& capabilities) { + return validatedConvert(capabilities); +} + +GeneralResult convert(const hal::V1_1::Model& model) { + return validatedConvert(model); +} + +GeneralResult convert( + const hal::V1_1::ExecutionPreference& executionPreference) { + return validatedConvert(executionPreference); +} + } // namespace android::nn namespace android::hardware::neuralnetworks::V1_1::utils { namespace { -using utils::convert; +using utils::unvalidatedConvert; -nn::GeneralResult convert( +nn::GeneralResult unvalidatedConvert( const nn::Capabilities::PerformanceInfo& performanceInfo) { - return V1_0::utils::convert(performanceInfo); + return V1_0::utils::unvalidatedConvert(performanceInfo); } -nn::GeneralResult convert(const nn::Operand& operand) { - return V1_0::utils::convert(operand); +nn::GeneralResult unvalidatedConvert(const nn::Operand& operand) { + return V1_0::utils::unvalidatedConvert(operand); } -nn::GeneralResult> convert(const nn::Model::OperandValues& operandValues) { - return V1_0::utils::convert(operandValues); +nn::GeneralResult> unvalidatedConvert( + const nn::Model::OperandValues& operandValues) { + return V1_0::utils::unvalidatedConvert(operandValues); } -nn::GeneralResult convert(const nn::Memory& memory) { - return V1_0::utils::convert(memory); +nn::GeneralResult unvalidatedConvert(const nn::Memory& memory) { + return V1_0::utils::unvalidatedConvert(memory); } template -using convertOutput = std::decay_t()).value())>; +using unvalidatedConvertOutput = + std::decay_t()).value())>; template -nn::GeneralResult>> convert(const std::vector& arguments) { - hidl_vec> halObject(arguments.size()); +nn::GeneralResult>> unvalidatedConvert( + const std::vector& arguments) { + hidl_vec> halObject(arguments.size()); for (size_t i = 0; i < arguments.size(); ++i) { - halObject[i] = NN_TRY(convert(arguments[i])); + halObject[i] = NN_TRY(unvalidatedConvert(arguments[i])); } return halObject; } +template +decltype(utils::unvalidatedConvert(std::declval())) validatedConvert(const Type& canonical) { + const auto maybeVersion = nn::validate(canonical); + if (!maybeVersion.has_value()) { + return nn::error() << maybeVersion.error(); + } + const auto version = maybeVersion.value(); + if (version > kVersion) { + return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion; + } + return utils::unvalidatedConvert(canonical); +} + } // anonymous namespace -nn::GeneralResult convert(const nn::OperationType& operationType) { +nn::GeneralResult unvalidatedConvert(const nn::OperationType& operationType) { return static_cast(operationType); } -nn::GeneralResult convert(const nn::Capabilities& capabilities) { +nn::GeneralResult unvalidatedConvert(const nn::Capabilities& capabilities) { return Capabilities{ - .float32Performance = NN_TRY(convert( + .float32Performance = NN_TRY(unvalidatedConvert( capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_FLOAT32))), - .quantized8Performance = NN_TRY(convert( + .quantized8Performance = NN_TRY(unvalidatedConvert( capabilities.operandPerformance.lookup(nn::OperandType::TENSOR_QUANT8_ASYMM))), - .relaxedFloat32toFloat16Performance = - NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor)), + .relaxedFloat32toFloat16Performance = NN_TRY( + unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)), }; } -nn::GeneralResult convert(const nn::Operation& operation) { +nn::GeneralResult unvalidatedConvert(const nn::Operation& operation) { return Operation{ - .type = NN_TRY(convert(operation.type)), + .type = NN_TRY(unvalidatedConvert(operation.type)), .inputs = operation.inputs, .outputs = operation.outputs, }; } -nn::GeneralResult convert(const nn::Model& model) { +nn::GeneralResult unvalidatedConvert(const nn::Model& model) { if (!hal::utils::hasNoPointerData(model)) { return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) - << "Mdoel cannot be converted because it contains pointer-based memory"; + << "Mdoel cannot be unvalidatedConverted because it contains pointer-based memory"; } - auto operands = NN_TRY(convert(model.main.operands)); + auto operands = NN_TRY(unvalidatedConvert(model.main.operands)); // Update number of consumers. const auto numberOfConsumers = @@ -195,17 +249,30 @@ nn::GeneralResult convert(const nn::Model& model) { return Model{ .operands = std::move(operands), - .operations = NN_TRY(convert(model.main.operations)), + .operations = NN_TRY(unvalidatedConvert(model.main.operations)), .inputIndexes = model.main.inputIndexes, .outputIndexes = model.main.outputIndexes, - .operandValues = NN_TRY(convert(model.operandValues)), - .pools = NN_TRY(convert(model.pools)), + .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)), + .pools = NN_TRY(unvalidatedConvert(model.pools)), .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16, }; } -nn::GeneralResult convert(const nn::ExecutionPreference& executionPreference) { +nn::GeneralResult unvalidatedConvert( + const nn::ExecutionPreference& executionPreference) { return static_cast(executionPreference); } +nn::GeneralResult convert(const nn::Capabilities& capabilities) { + return validatedConvert(capabilities); +} + +nn::GeneralResult convert(const nn::Model& model) { + return validatedConvert(model); +} + +nn::GeneralResult convert(const nn::ExecutionPreference& executionPreference) { + return validatedConvert(executionPreference); +} + } // namespace android::hardware::neuralnetworks::V1_1::utils diff --git a/neuralnetworks/1.1/utils/src/Device.cpp b/neuralnetworks/1.1/utils/src/Device.cpp index a0378c94a0..e45b17ec6e 100644 --- a/neuralnetworks/1.1/utils/src/Device.cpp +++ b/neuralnetworks/1.1/utils/src/Device.cpp @@ -49,11 +49,10 @@ nn::GeneralResult initCapabilities(V1_1::IDevice* device) { << "uninitialized"; const auto cb = [&result](V1_0::ErrorStatus status, const Capabilities& capabilities) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "getCapabilities_1_1 failed with " << toString(status); } else { - result = validatedConvertToCanonical(capabilities); + result = nn::convert(capabilities); } }; @@ -137,8 +136,7 @@ nn::GeneralResult> Device::getSupportedOperations(const nn::Mo auto cb = [&result, &model](V1_0::ErrorStatus status, const hidl_vec& supportedOperations) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "getSupportedOperations_1_1 failed with " << toString(status); } else if (supportedOperations.size() != model.main.operations.size()) { @@ -175,8 +173,7 @@ nn::GeneralResult Device::prepareModel( const auto ret = kDevice->prepareModel_1_1(hidlModel, hidlPreference, cb); const auto status = NN_TRY(hal::utils::handleTransportError(ret)); if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); return NN_ERROR(canonical) << "prepareModel failed with " << toString(status); } diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h index 24911fea08..5dcbc0bb79 100644 --- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h +++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Conversions.h @@ -24,27 +24,34 @@ namespace android::nn { -GeneralResult convert(const hal::V1_2::OperandType& operandType); -GeneralResult convert(const hal::V1_2::OperationType& operationType); +GeneralResult unvalidatedConvert(const hal::V1_2::OperandType& operandType); +GeneralResult unvalidatedConvert(const hal::V1_2::OperationType& operationType); +GeneralResult unvalidatedConvert(const hal::V1_2::DeviceType& deviceType); +GeneralResult unvalidatedConvert(const hal::V1_2::Capabilities& capabilities); +GeneralResult unvalidatedConvert( + const hal::V1_2::Capabilities::OperandPerformance& operandPerformance); +GeneralResult unvalidatedConvert(const hal::V1_2::Operation& operation); +GeneralResult unvalidatedConvert( + const hal::V1_2::SymmPerChannelQuantParams& symmPerChannelQuantParams); +GeneralResult unvalidatedConvert(const hal::V1_2::Operand& operand); +GeneralResult unvalidatedConvert( + const hal::V1_2::Operand::ExtraParams& extraParams); +GeneralResult unvalidatedConvert(const hal::V1_2::Model& model); +GeneralResult unvalidatedConvert( + const hal::V1_2::Model::ExtensionNameAndPrefix& extensionNameAndPrefix); +GeneralResult unvalidatedConvert(const hal::V1_2::OutputShape& outputShape); +GeneralResult unvalidatedConvert(const hal::V1_2::MeasureTiming& measureTiming); +GeneralResult unvalidatedConvert(const hal::V1_2::Timing& timing); +GeneralResult unvalidatedConvert(const hal::V1_2::Extension& extension); +GeneralResult unvalidatedConvert( + const hal::V1_2::Extension::OperandTypeInformation& operandTypeInformation); +GeneralResult unvalidatedConvert(const hardware::hidl_handle& handle); + GeneralResult convert(const hal::V1_2::DeviceType& deviceType); GeneralResult convert(const hal::V1_2::Capabilities& capabilities); -GeneralResult convert( - const hal::V1_2::Capabilities::OperandPerformance& operandPerformance); -GeneralResult convert(const hal::V1_2::Operation& operation); -GeneralResult convert( - const hal::V1_2::SymmPerChannelQuantParams& symmPerChannelQuantParams); -GeneralResult convert(const hal::V1_2::Operand& operand); -GeneralResult convert(const hal::V1_2::Operand::ExtraParams& extraParams); GeneralResult convert(const hal::V1_2::Model& model); -GeneralResult convert( - const hal::V1_2::Model::ExtensionNameAndPrefix& extensionNameAndPrefix); -GeneralResult convert(const hal::V1_2::OutputShape& outputShape); GeneralResult convert(const hal::V1_2::MeasureTiming& measureTiming); GeneralResult convert(const hal::V1_2::Timing& timing); -GeneralResult convert(const hal::V1_2::Extension& extension); -GeneralResult convert( - const hal::V1_2::Extension::OperandTypeInformation& operandTypeInformation); -GeneralResult convert(const hardware::hidl_handle& handle); GeneralResult> convert( const hardware::hidl_vec& extensions); @@ -57,27 +64,34 @@ GeneralResult> convert( namespace android::hardware::neuralnetworks::V1_2::utils { -nn::GeneralResult convert(const nn::OperandType& operandType); -nn::GeneralResult convert(const nn::OperationType& operationType); +nn::GeneralResult unvalidatedConvert(const nn::OperandType& operandType); +nn::GeneralResult unvalidatedConvert(const nn::OperationType& operationType); +nn::GeneralResult unvalidatedConvert(const nn::DeviceType& deviceType); +nn::GeneralResult unvalidatedConvert(const nn::Capabilities& capabilities); +nn::GeneralResult unvalidatedConvert( + const nn::Capabilities::OperandPerformance& operandPerformance); +nn::GeneralResult unvalidatedConvert(const nn::Operation& operation); +nn::GeneralResult unvalidatedConvert( + const nn::Operand::SymmPerChannelQuantParams& symmPerChannelQuantParams); +nn::GeneralResult unvalidatedConvert(const nn::Operand& operand); +nn::GeneralResult unvalidatedConvert( + const nn::Operand::ExtraParams& extraParams); +nn::GeneralResult unvalidatedConvert(const nn::Model& model); +nn::GeneralResult unvalidatedConvert( + const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix); +nn::GeneralResult unvalidatedConvert(const nn::OutputShape& outputShape); +nn::GeneralResult unvalidatedConvert(const nn::MeasureTiming& measureTiming); +nn::GeneralResult unvalidatedConvert(const nn::Timing& timing); +nn::GeneralResult unvalidatedConvert(const nn::Extension& extension); +nn::GeneralResult unvalidatedConvert( + const nn::Extension::OperandTypeInformation& operandTypeInformation); +nn::GeneralResult unvalidatedConvert(const nn::SharedHandle& handle); + nn::GeneralResult convert(const nn::DeviceType& deviceType); nn::GeneralResult convert(const nn::Capabilities& capabilities); -nn::GeneralResult convert( - const nn::Capabilities::OperandPerformance& operandPerformance); -nn::GeneralResult convert(const nn::Operation& operation); -nn::GeneralResult convert( - const nn::Operand::SymmPerChannelQuantParams& symmPerChannelQuantParams); -nn::GeneralResult convert(const nn::Operand& operand); -nn::GeneralResult convert(const nn::Operand::ExtraParams& extraParams); nn::GeneralResult convert(const nn::Model& model); -nn::GeneralResult convert( - const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix); -nn::GeneralResult convert(const nn::OutputShape& outputShape); nn::GeneralResult convert(const nn::MeasureTiming& measureTiming); nn::GeneralResult convert(const nn::Timing& timing); -nn::GeneralResult convert(const nn::Extension& extension); -nn::GeneralResult convert( - const nn::Extension::OperandTypeInformation& operandTypeInformation); -nn::GeneralResult convert(const nn::SharedHandle& handle); nn::GeneralResult> convert(const std::vector& extensions); nn::GeneralResult> convert(const std::vector& handles); diff --git a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h index a9a6baeccc..70149a2d3a 100644 --- a/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h +++ b/neuralnetworks/1.2/utils/include/nnapi/hal/1.2/Utils.h @@ -22,9 +22,7 @@ #include #include #include -#include #include -#include #include #include @@ -35,7 +33,6 @@ namespace android::hardware::neuralnetworks::V1_2::utils { constexpr auto kDefaultMesaureTiming = MeasureTiming::NO; constexpr auto kNoTiming = Timing{.timeOnDevice = std::numeric_limits::max(), .timeInDriver = std::numeric_limits::max()}; -constexpr auto kVersion = nn::Version::ANDROID_Q; template nn::Result validate(const Type& halObject) { @@ -43,11 +40,6 @@ nn::Result validate(const Type& halObject) { if (!maybeCanonical.has_value()) { return nn::error() << maybeCanonical.error().message; } - const auto version = NN_TRY(nn::validate(maybeCanonical.value())); - if (version > utils::kVersion) { - return NN_ERROR() << "Insufficient version: " << version << " vs required " - << utils::kVersion; - } return {}; } @@ -60,21 +52,6 @@ bool valid(const Type& halObject) { return result.has_value(); } -template -decltype(nn::convert(std::declval())) validatedConvertToCanonical(const Type& halObject) { - auto canonical = NN_TRY(nn::convert(halObject)); - const auto maybeVersion = nn::validate(canonical); - if (!maybeVersion.has_value()) { - return nn::error() << maybeVersion.error(); - } - const auto version = maybeVersion.value(); - if (version > utils::kVersion) { - return NN_ERROR() << "Insufficient version: " << version << " vs required " - << utils::kVersion; - } - return canonical; -} - } // namespace android::hardware::neuralnetworks::V1_2::utils #endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_2_UTILS_H diff --git a/neuralnetworks/1.2/utils/src/Callbacks.cpp b/neuralnetworks/1.2/utils/src/Callbacks.cpp index cb739f0eeb..39f88c2c5e 100644 --- a/neuralnetworks/1.2/utils/src/Callbacks.cpp +++ b/neuralnetworks/1.2/utils/src/Callbacks.cpp @@ -52,8 +52,7 @@ nn::GeneralResult convertPreparedModel( nn::GeneralResult, nn::Timing>> convertExecutionGeneralResultsHelper(const hidl_vec& outputShapes, const Timing& timing) { - return std::make_pair(NN_TRY(validatedConvertToCanonical(outputShapes)), - NN_TRY(validatedConvertToCanonical(timing))); + return std::make_pair(NN_TRY(nn::convert(outputShapes)), NN_TRY(nn::convert(timing))); } nn::ExecutionResult, nn::Timing>> @@ -67,8 +66,7 @@ convertExecutionGeneralResults(const hidl_vec& outputShapes, const Return PreparedModelCallback::notify(V1_0::ErrorStatus status, const sp& preparedModel) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status)); } else if (preparedModel == nullptr) { notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) @@ -82,8 +80,7 @@ Return PreparedModelCallback::notify(V1_0::ErrorStatus status, Return PreparedModelCallback::notify_1_2(V1_0::ErrorStatus status, const sp& preparedModel) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status)); } else if (preparedModel == nullptr) { notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) @@ -110,8 +107,7 @@ void PreparedModelCallback::notifyInternal(PreparedModelCallback::Data result) { Return ExecutionCallback::notify(V1_0::ErrorStatus status) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status)); } else { notifyInternal({}); @@ -123,8 +119,7 @@ Return ExecutionCallback::notify_1_2(V1_0::ErrorStatus status, const hidl_vec& outputShapes, const Timing& timing) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status)); } else { notifyInternal(convertExecutionGeneralResults(outputShapes, timing)); diff --git a/neuralnetworks/1.2/utils/src/Conversions.cpp b/neuralnetworks/1.2/utils/src/Conversions.cpp index 08c94dec33..f11474fd60 100644 --- a/neuralnetworks/1.2/utils/src/Conversions.cpp +++ b/neuralnetworks/1.2/utils/src/Conversions.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -42,6 +43,8 @@ constexpr std::underlying_type_t underlyingType(Type value) { return static_cast>(value); } +constexpr auto kVersion = android::nn::Version::ANDROID_Q; + } // namespace namespace android::nn { @@ -76,42 +79,70 @@ using hardware::hidl_handle; using hardware::hidl_vec; template -using ConvertOutput = std::decay_t()).value())>; +using unvalidatedConvertOutput = + std::decay_t()).value())>; template -GeneralResult>> convertVec(const hidl_vec& arguments) { - std::vector> canonical; +GeneralResult>> unvalidatedConvertVec( + const hidl_vec& arguments) { + std::vector> canonical; canonical.reserve(arguments.size()); for (const auto& argument : arguments) { - canonical.push_back(NN_TRY(nn::convert(argument))); + canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument))); } return canonical; } template -GeneralResult>> convert(const hidl_vec& arguments) { - return convertVec(arguments); +GeneralResult>> unvalidatedConvert( + const hidl_vec& arguments) { + return unvalidatedConvertVec(arguments); +} + +template +decltype(nn::unvalidatedConvert(std::declval())) validatedConvert(const Type& halObject) { + auto canonical = NN_TRY(nn::unvalidatedConvert(halObject)); + const auto maybeVersion = validate(canonical); + if (!maybeVersion.has_value()) { + return error() << maybeVersion.error(); + } + const auto version = maybeVersion.value(); + if (version > kVersion) { + return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion; + } + return canonical; +} + +template +GeneralResult>> validatedConvert( + const hidl_vec& arguments) { + std::vector> canonical; + canonical.reserve(arguments.size()); + for (const auto& argument : arguments) { + canonical.push_back(NN_TRY(validatedConvert(argument))); + } + return canonical; } } // anonymous namespace -GeneralResult convert(const hal::V1_2::OperandType& operandType) { +GeneralResult unvalidatedConvert(const hal::V1_2::OperandType& operandType) { return static_cast(operandType); } -GeneralResult convert(const hal::V1_2::OperationType& operationType) { +GeneralResult unvalidatedConvert(const hal::V1_2::OperationType& operationType) { return static_cast(operationType); } -GeneralResult convert(const hal::V1_2::DeviceType& deviceType) { +GeneralResult unvalidatedConvert(const hal::V1_2::DeviceType& deviceType) { return static_cast(deviceType); } -GeneralResult convert(const hal::V1_2::Capabilities& capabilities) { +GeneralResult unvalidatedConvert(const hal::V1_2::Capabilities& capabilities) { const bool validOperandTypes = std::all_of( capabilities.operandPerformance.begin(), capabilities.operandPerformance.end(), [](const hal::V1_2::Capabilities::OperandPerformance& operandPerformance) { - const auto maybeType = convert(operandPerformance.type); + const auto maybeType = unvalidatedConvert(operandPerformance.type); return !maybeType.has_value() ? false : validOperandType(maybeType.value()); }); if (!validOperandTypes) { @@ -120,10 +151,10 @@ GeneralResult convert(const hal::V1_2::Capabilities& capabilities) } const auto relaxedFloat32toFloat16PerformanceScalar = - NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceScalar)); + NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)); const auto relaxedFloat32toFloat16PerformanceTensor = - NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor)); - auto operandPerformance = NN_TRY(convert(capabilities.operandPerformance)); + NN_TRY(unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)); + auto operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance)); auto table = NN_TRY(hal::utils::makeGeneralFailure( Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)), @@ -136,23 +167,23 @@ GeneralResult convert(const hal::V1_2::Capabilities& capabilities) }; } -GeneralResult convert( +GeneralResult unvalidatedConvert( const hal::V1_2::Capabilities::OperandPerformance& operandPerformance) { return Capabilities::OperandPerformance{ - .type = NN_TRY(convert(operandPerformance.type)), - .info = NN_TRY(convert(operandPerformance.info)), + .type = NN_TRY(unvalidatedConvert(operandPerformance.type)), + .info = NN_TRY(unvalidatedConvert(operandPerformance.info)), }; } -GeneralResult convert(const hal::V1_2::Operation& operation) { +GeneralResult unvalidatedConvert(const hal::V1_2::Operation& operation) { return Operation{ - .type = NN_TRY(convert(operation.type)), + .type = NN_TRY(unvalidatedConvert(operation.type)), .inputs = operation.inputs, .outputs = operation.outputs, }; } -GeneralResult convert( +GeneralResult unvalidatedConvert( const hal::V1_2::SymmPerChannelQuantParams& symmPerChannelQuantParams) { return Operand::SymmPerChannelQuantParams{ .scales = symmPerChannelQuantParams.scales, @@ -160,25 +191,26 @@ GeneralResult convert( }; } -GeneralResult convert(const hal::V1_2::Operand& operand) { +GeneralResult unvalidatedConvert(const hal::V1_2::Operand& operand) { return Operand{ - .type = NN_TRY(convert(operand.type)), + .type = NN_TRY(unvalidatedConvert(operand.type)), .dimensions = operand.dimensions, .scale = operand.scale, .zeroPoint = operand.zeroPoint, - .lifetime = NN_TRY(convert(operand.lifetime)), - .location = NN_TRY(convert(operand.location)), - .extraParams = NN_TRY(convert(operand.extraParams)), + .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)), + .location = NN_TRY(unvalidatedConvert(operand.location)), + .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)), }; } -GeneralResult convert(const hal::V1_2::Operand::ExtraParams& extraParams) { +GeneralResult unvalidatedConvert( + const hal::V1_2::Operand::ExtraParams& extraParams) { using Discriminator = hal::V1_2::Operand::ExtraParams::hidl_discriminator; switch (extraParams.getDiscriminator()) { case Discriminator::none: return Operand::NoParams{}; case Discriminator::channelQuant: - return convert(extraParams.channelQuant()); + return unvalidatedConvert(extraParams.channelQuant()); case Discriminator::extension: return extraParams.extension(); } @@ -187,8 +219,8 @@ GeneralResult convert(const hal::V1_2::Operand::ExtraParam << underlyingType(extraParams.getDiscriminator()); } -GeneralResult convert(const hal::V1_2::Model& model) { - auto operations = NN_TRY(convert(model.operations)); +GeneralResult unvalidatedConvert(const hal::V1_2::Model& model) { + auto operations = NN_TRY(unvalidatedConvert(model.operations)); // Verify number of consumers. const auto numberOfConsumers = @@ -203,7 +235,7 @@ GeneralResult convert(const hal::V1_2::Model& model) { } auto main = Model::Subgraph{ - .operands = NN_TRY(convert(model.operands)), + .operands = NN_TRY(unvalidatedConvert(model.operands)), .operations = std::move(operations), .inputIndexes = model.inputIndexes, .outputIndexes = model.outputIndexes, @@ -211,14 +243,14 @@ GeneralResult convert(const hal::V1_2::Model& model) { return Model{ .main = std::move(main), - .operandValues = NN_TRY(convert(model.operandValues)), - .pools = NN_TRY(convert(model.pools)), + .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)), + .pools = NN_TRY(unvalidatedConvert(model.pools)), .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16, - .extensionNameToPrefix = NN_TRY(convert(model.extensionNameToPrefix)), + .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)), }; } -GeneralResult convert( +GeneralResult unvalidatedConvert( const hal::V1_2::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) { return Model::ExtensionNameAndPrefix{ .name = extensionNameAndPrefix.name, @@ -226,29 +258,29 @@ GeneralResult convert( }; } -GeneralResult convert(const hal::V1_2::OutputShape& outputShape) { +GeneralResult unvalidatedConvert(const hal::V1_2::OutputShape& outputShape) { return OutputShape{ .dimensions = outputShape.dimensions, .isSufficient = outputShape.isSufficient, }; } -GeneralResult convert(const hal::V1_2::MeasureTiming& measureTiming) { +GeneralResult unvalidatedConvert(const hal::V1_2::MeasureTiming& measureTiming) { return static_cast(measureTiming); } -GeneralResult convert(const hal::V1_2::Timing& timing) { +GeneralResult unvalidatedConvert(const hal::V1_2::Timing& timing) { return Timing{.timeOnDevice = timing.timeOnDevice, .timeInDriver = timing.timeInDriver}; } -GeneralResult convert(const hal::V1_2::Extension& extension) { +GeneralResult unvalidatedConvert(const hal::V1_2::Extension& extension) { return Extension{ .name = extension.name, - .operandTypes = NN_TRY(convert(extension.operandTypes)), + .operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes)), }; } -GeneralResult convert( +GeneralResult unvalidatedConvert( const hal::V1_2::Extension::OperandTypeInformation& operandTypeInformation) { return Extension::OperandTypeInformation{ .type = operandTypeInformation.type, @@ -257,21 +289,41 @@ GeneralResult convert( }; } -GeneralResult convert(const hidl_handle& hidlHandle) { +GeneralResult unvalidatedConvert(const hidl_handle& hidlHandle) { return hal::utils::sharedHandleFromNativeHandle(hidlHandle.getNativeHandle()); } +GeneralResult convert(const hal::V1_2::DeviceType& deviceType) { + return validatedConvert(deviceType); +} + +GeneralResult convert(const hal::V1_2::Capabilities& capabilities) { + return validatedConvert(capabilities); +} + +GeneralResult convert(const hal::V1_2::Model& model) { + return validatedConvert(model); +} + +GeneralResult convert(const hal::V1_2::MeasureTiming& measureTiming) { + return validatedConvert(measureTiming); +} + +GeneralResult convert(const hal::V1_2::Timing& timing) { + return validatedConvert(timing); +} + GeneralResult> convert(const hidl_vec& extensions) { - return convertVec(extensions); + return validatedConvert(extensions); } GeneralResult> convert(const hidl_vec& handles) { - return convertVec(handles); + return validatedConvert(handles); } GeneralResult> convert( const hidl_vec& outputShapes) { - return convertVec(outputShapes); + return validatedConvert(outputShapes); } } // namespace android::nn @@ -279,44 +331,48 @@ GeneralResult> convert( namespace android::hardware::neuralnetworks::V1_2::utils { namespace { -using utils::convert; +using utils::unvalidatedConvert; -nn::GeneralResult convert(const nn::Operand::LifeTime& lifetime) { - return V1_0::utils::convert(lifetime); +nn::GeneralResult unvalidatedConvert(const nn::Operand::LifeTime& lifetime) { + return V1_0::utils::unvalidatedConvert(lifetime); } -nn::GeneralResult convert( +nn::GeneralResult unvalidatedConvert( const nn::Capabilities::PerformanceInfo& performanceInfo) { - return V1_0::utils::convert(performanceInfo); + return V1_0::utils::unvalidatedConvert(performanceInfo); } -nn::GeneralResult convert(const nn::DataLocation& location) { - return V1_0::utils::convert(location); +nn::GeneralResult unvalidatedConvert(const nn::DataLocation& location) { + return V1_0::utils::unvalidatedConvert(location); } -nn::GeneralResult> convert(const nn::Model::OperandValues& operandValues) { - return V1_0::utils::convert(operandValues); +nn::GeneralResult> unvalidatedConvert( + const nn::Model::OperandValues& operandValues) { + return V1_0::utils::unvalidatedConvert(operandValues); } -nn::GeneralResult convert(const nn::Memory& memory) { - return V1_0::utils::convert(memory); +nn::GeneralResult unvalidatedConvert(const nn::Memory& memory) { + return V1_0::utils::unvalidatedConvert(memory); } template -using ConvertOutput = std::decay_t()).value())>; +using unvalidatedConvertOutput = + std::decay_t()).value())>; template -nn::GeneralResult>> convertVec(const std::vector& arguments) { - hidl_vec> halObject(arguments.size()); +nn::GeneralResult>> unvalidatedConvertVec( + const std::vector& arguments) { + hidl_vec> halObject(arguments.size()); for (size_t i = 0; i < arguments.size(); ++i) { - halObject[i] = NN_TRY(convert(arguments[i])); + halObject[i] = NN_TRY(unvalidatedConvert(arguments[i])); } return halObject; } template -nn::GeneralResult>> convert(const std::vector& arguments) { - return convertVec(arguments); +nn::GeneralResult>> unvalidatedConvert( + const std::vector& arguments) { + return unvalidatedConvertVec(arguments); } nn::GeneralResult makeExtraParams(nn::Operand::NoParams /*noParams*/) { @@ -326,7 +382,7 @@ nn::GeneralResult makeExtraParams(nn::Operand::NoParams /* nn::GeneralResult makeExtraParams( const nn::Operand::SymmPerChannelQuantParams& channelQuant) { Operand::ExtraParams ret; - ret.channelQuant(NN_TRY(convert(channelQuant))); + ret.channelQuant(NN_TRY(unvalidatedConvert(channelQuant))); return ret; } @@ -337,17 +393,40 @@ nn::GeneralResult makeExtraParams( return ret; } +template +decltype(utils::unvalidatedConvert(std::declval())) validatedConvert(const Type& canonical) { + const auto maybeVersion = nn::validate(canonical); + if (!maybeVersion.has_value()) { + return nn::error() << maybeVersion.error(); + } + const auto version = maybeVersion.value(); + if (version > kVersion) { + return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion; + } + return utils::unvalidatedConvert(canonical); +} + +template +nn::GeneralResult>> validatedConvert( + const std::vector& arguments) { + hidl_vec> halObject(arguments.size()); + for (size_t i = 0; i < arguments.size(); ++i) { + halObject[i] = NN_TRY(validatedConvert(arguments[i])); + } + return halObject; +} + } // anonymous namespace -nn::GeneralResult convert(const nn::OperandType& operandType) { +nn::GeneralResult unvalidatedConvert(const nn::OperandType& operandType) { return static_cast(operandType); } -nn::GeneralResult convert(const nn::OperationType& operationType) { +nn::GeneralResult unvalidatedConvert(const nn::OperationType& operationType) { return static_cast(operationType); } -nn::GeneralResult convert(const nn::DeviceType& deviceType) { +nn::GeneralResult unvalidatedConvert(const nn::DeviceType& deviceType) { switch (deviceType) { case nn::DeviceType::UNKNOWN: return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Invalid DeviceType UNKNOWN"; @@ -361,7 +440,7 @@ nn::GeneralResult convert(const nn::DeviceType& deviceType) { << "Invalid DeviceType " << underlyingType(deviceType); } -nn::GeneralResult convert(const nn::Capabilities& capabilities) { +nn::GeneralResult unvalidatedConvert(const nn::Capabilities& capabilities) { std::vector operandPerformance; operandPerformance.reserve(capabilities.operandPerformance.asVector().size()); std::copy_if(capabilities.operandPerformance.asVector().begin(), @@ -372,31 +451,31 @@ nn::GeneralResult convert(const nn::Capabilities& capabilities) { }); return Capabilities{ - .relaxedFloat32toFloat16PerformanceScalar = - NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceScalar)), - .relaxedFloat32toFloat16PerformanceTensor = - NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor)), - .operandPerformance = NN_TRY(convert(operandPerformance)), + .relaxedFloat32toFloat16PerformanceScalar = NN_TRY( + unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)), + .relaxedFloat32toFloat16PerformanceTensor = NN_TRY( + unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)), + .operandPerformance = NN_TRY(unvalidatedConvert(operandPerformance)), }; } -nn::GeneralResult convert( +nn::GeneralResult unvalidatedConvert( const nn::Capabilities::OperandPerformance& operandPerformance) { return Capabilities::OperandPerformance{ - .type = NN_TRY(convert(operandPerformance.type)), - .info = NN_TRY(convert(operandPerformance.info)), + .type = NN_TRY(unvalidatedConvert(operandPerformance.type)), + .info = NN_TRY(unvalidatedConvert(operandPerformance.info)), }; } -nn::GeneralResult convert(const nn::Operation& operation) { +nn::GeneralResult unvalidatedConvert(const nn::Operation& operation) { return Operation{ - .type = NN_TRY(convert(operation.type)), + .type = NN_TRY(unvalidatedConvert(operation.type)), .inputs = operation.inputs, .outputs = operation.outputs, }; } -nn::GeneralResult convert( +nn::GeneralResult unvalidatedConvert( const nn::Operand::SymmPerChannelQuantParams& symmPerChannelQuantParams) { return SymmPerChannelQuantParams{ .scales = symmPerChannelQuantParams.scales, @@ -404,30 +483,31 @@ nn::GeneralResult convert( }; } -nn::GeneralResult convert(const nn::Operand& operand) { +nn::GeneralResult unvalidatedConvert(const nn::Operand& operand) { return Operand{ - .type = NN_TRY(convert(operand.type)), + .type = NN_TRY(unvalidatedConvert(operand.type)), .dimensions = operand.dimensions, .numberOfConsumers = 0, .scale = operand.scale, .zeroPoint = operand.zeroPoint, - .lifetime = NN_TRY(convert(operand.lifetime)), - .location = NN_TRY(convert(operand.location)), - .extraParams = NN_TRY(convert(operand.extraParams)), + .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)), + .location = NN_TRY(unvalidatedConvert(operand.location)), + .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)), }; } -nn::GeneralResult convert(const nn::Operand::ExtraParams& extraParams) { +nn::GeneralResult unvalidatedConvert( + const nn::Operand::ExtraParams& extraParams) { return std::visit([](const auto& x) { return makeExtraParams(x); }, extraParams); } -nn::GeneralResult convert(const nn::Model& model) { +nn::GeneralResult unvalidatedConvert(const nn::Model& model) { if (!hal::utils::hasNoPointerData(model)) { return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) - << "Model cannot be converted because it contains pointer-based memory"; + << "Model cannot be unvalidatedConverted because it contains pointer-based memory"; } - auto operands = NN_TRY(convert(model.main.operands)); + auto operands = NN_TRY(unvalidatedConvert(model.main.operands)); // Update number of consumers. const auto numberOfConsumers = @@ -439,17 +519,17 @@ nn::GeneralResult convert(const nn::Model& model) { return Model{ .operands = std::move(operands), - .operations = NN_TRY(convert(model.main.operations)), + .operations = NN_TRY(unvalidatedConvert(model.main.operations)), .inputIndexes = model.main.inputIndexes, .outputIndexes = model.main.outputIndexes, - .operandValues = NN_TRY(convert(model.operandValues)), - .pools = NN_TRY(convert(model.pools)), + .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)), + .pools = NN_TRY(unvalidatedConvert(model.pools)), .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16, - .extensionNameToPrefix = NN_TRY(convert(model.extensionNameToPrefix)), + .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)), }; } -nn::GeneralResult convert( +nn::GeneralResult unvalidatedConvert( const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) { return Model::ExtensionNameAndPrefix{ .name = extensionNameAndPrefix.name, @@ -457,27 +537,27 @@ nn::GeneralResult convert( }; } -nn::GeneralResult convert(const nn::OutputShape& outputShape) { +nn::GeneralResult unvalidatedConvert(const nn::OutputShape& outputShape) { return OutputShape{.dimensions = outputShape.dimensions, .isSufficient = outputShape.isSufficient}; } -nn::GeneralResult convert(const nn::MeasureTiming& measureTiming) { +nn::GeneralResult unvalidatedConvert(const nn::MeasureTiming& measureTiming) { return static_cast(measureTiming); } -nn::GeneralResult convert(const nn::Timing& timing) { +nn::GeneralResult unvalidatedConvert(const nn::Timing& timing) { return Timing{.timeOnDevice = timing.timeOnDevice, .timeInDriver = timing.timeInDriver}; } -nn::GeneralResult convert(const nn::Extension& extension) { +nn::GeneralResult unvalidatedConvert(const nn::Extension& extension) { return Extension{ .name = extension.name, - .operandTypes = NN_TRY(convert(extension.operandTypes)), + .operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes)), }; } -nn::GeneralResult convert( +nn::GeneralResult unvalidatedConvert( const nn::Extension::OperandTypeInformation& operandTypeInformation) { return Extension::OperandTypeInformation{ .type = operandTypeInformation.type, @@ -486,20 +566,40 @@ nn::GeneralResult convert( }; } -nn::GeneralResult convert(const nn::SharedHandle& handle) { +nn::GeneralResult unvalidatedConvert(const nn::SharedHandle& handle) { return hal::utils::hidlHandleFromSharedHandle(handle); } +nn::GeneralResult convert(const nn::DeviceType& deviceType) { + return validatedConvert(deviceType); +} + +nn::GeneralResult convert(const nn::Capabilities& capabilities) { + return validatedConvert(capabilities); +} + +nn::GeneralResult convert(const nn::Model& model) { + return validatedConvert(model); +} + +nn::GeneralResult convert(const nn::MeasureTiming& measureTiming) { + return validatedConvert(measureTiming); +} + +nn::GeneralResult convert(const nn::Timing& timing) { + return validatedConvert(timing); +} + nn::GeneralResult> convert(const std::vector& extensions) { - return convertVec(extensions); + return validatedConvert(extensions); } nn::GeneralResult> convert(const std::vector& handles) { - return convertVec(handles); + return validatedConvert(handles); } nn::GeneralResult> convert(const std::vector& outputShapes) { - return convertVec(outputShapes); + return validatedConvert(outputShapes); } } // namespace android::hardware::neuralnetworks::V1_2::utils diff --git a/neuralnetworks/1.2/utils/src/Device.cpp b/neuralnetworks/1.2/utils/src/Device.cpp index a9e537752e..967a252c88 100644 --- a/neuralnetworks/1.2/utils/src/Device.cpp +++ b/neuralnetworks/1.2/utils/src/Device.cpp @@ -51,11 +51,10 @@ nn::GeneralResult initCapabilities(V1_2::IDevice* device) { << "uninitialized"; const auto cb = [&result](V1_0::ErrorStatus status, const Capabilities& capabilities) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "getCapabilities_1_2 failed with " << toString(status); } else { - result = validatedConvertToCanonical(capabilities); + result = nn::convert(capabilities); } }; @@ -74,8 +73,7 @@ nn::GeneralResult initVersionString(V1_2::IDevice* device) { << "uninitialized"; const auto cb = [&result](V1_0::ErrorStatus status, const hidl_string& versionString) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "getVersionString failed with " << toString(status); } else { result = versionString; @@ -95,8 +93,7 @@ nn::GeneralResult initDeviceType(V1_2::IDevice* device) { << "uninitialized"; const auto cb = [&result](V1_0::ErrorStatus status, DeviceType deviceType) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "getDeviceType failed with " << toString(status); } else { result = nn::convert(deviceType); @@ -116,8 +113,7 @@ nn::GeneralResult> initExtensions(V1_2::IDevice* devi NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "uninitialized"; const auto cb = [&result](V1_0::ErrorStatus status, const hidl_vec& extensions) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "getExtensions failed with " << toString(status); } else { result = nn::convert(extensions); @@ -139,8 +135,7 @@ nn::GeneralResult> initNumberOfCacheFilesNeeded( const auto cb = [&result](V1_0::ErrorStatus status, uint32_t numModelCache, uint32_t numDataCache) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "getNumberOfCacheFilesNeeded failed with " << toString(status); } else { @@ -238,8 +233,7 @@ nn::GeneralResult> Device::getSupportedOperations(const nn::Mo auto cb = [&result, &model](V1_0::ErrorStatus status, const hidl_vec& supportedOperations) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "getSupportedOperations_1_2 failed with " << toString(status); } else if (supportedOperations.size() != model.main.operations.size()) { @@ -280,8 +274,7 @@ nn::GeneralResult Device::prepareModel( hidlDataCache, hidlToken, cb); const auto status = NN_TRY(hal::utils::handleTransportError(ret)); if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); return NN_ERROR(canonical) << "prepareModel_1_2 failed with " << toString(status); } @@ -301,8 +294,7 @@ nn::GeneralResult Device::prepareModelFromCache( const auto ret = kDevice->prepareModelFromCache(hidlModelCache, hidlDataCache, hidlToken, cb); const auto status = NN_TRY(hal::utils::handleTransportError(ret)); if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); return NN_ERROR(canonical) << "prepareModelFromCache failed with " << toString(status); } diff --git a/neuralnetworks/1.2/utils/src/PreparedModel.cpp b/neuralnetworks/1.2/utils/src/PreparedModel.cpp index ff9db215a2..b5a3389e6c 100644 --- a/neuralnetworks/1.2/utils/src/PreparedModel.cpp +++ b/neuralnetworks/1.2/utils/src/PreparedModel.cpp @@ -42,8 +42,7 @@ namespace { nn::GeneralResult, nn::Timing>> convertExecutionResultsHelper(const hidl_vec& outputShapes, const Timing& timing) { - return std::make_pair(NN_TRY(validatedConvertToCanonical(outputShapes)), - NN_TRY(validatedConvertToCanonical(timing))); + return std::make_pair(NN_TRY(nn::convert(outputShapes)), NN_TRY(nn::convert(timing))); } nn::ExecutionResult, nn::Timing>> convertExecutionResults( @@ -76,8 +75,7 @@ PreparedModel::executeSynchronously(const V1_0::Request& request, MeasureTiming const auto cb = [&result](V1_0::ErrorStatus status, const hidl_vec& outputShapes, const Timing& timing) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "executeSynchronously failed with " << toString(status); } else { result = convertExecutionResults(outputShapes, timing); @@ -99,8 +97,7 @@ PreparedModel::executeAsynchronously(const V1_0::Request& request, MeasureTiming const auto status = NN_TRY(hal::utils::makeExecutionFailure(hal::utils::handleTransportError(ret))); if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); return NN_ERROR(canonical) << "execute failed with " << toString(status); } 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 64aa96e61a..9653a05da7 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 @@ -25,26 +25,41 @@ namespace android::nn { -GeneralResult convert(const hal::V1_3::OperandType& operandType); -GeneralResult convert(const hal::V1_3::OperationType& operationType); +GeneralResult unvalidatedConvert(const hal::V1_3::OperandType& operandType); +GeneralResult unvalidatedConvert(const hal::V1_3::OperationType& operationType); +GeneralResult unvalidatedConvert(const hal::V1_3::Priority& priority); +GeneralResult unvalidatedConvert(const hal::V1_3::Capabilities& capabilities); +GeneralResult unvalidatedConvert( + const hal::V1_3::Capabilities::OperandPerformance& operandPerformance); +GeneralResult unvalidatedConvert(const hal::V1_3::Operation& operation); +GeneralResult unvalidatedConvert( + const hal::V1_3::OperandLifeTime& operandLifeTime); +GeneralResult unvalidatedConvert(const hal::V1_3::Operand& operand); +GeneralResult unvalidatedConvert(const hal::V1_3::Model& model); +GeneralResult unvalidatedConvert(const hal::V1_3::Subgraph& subgraph); +GeneralResult unvalidatedConvert(const hal::V1_3::BufferDesc& bufferDesc); +GeneralResult unvalidatedConvert(const hal::V1_3::BufferRole& bufferRole); +GeneralResult unvalidatedConvert(const hal::V1_3::Request& request); +GeneralResult unvalidatedConvert( + const hal::V1_3::Request::MemoryPool& memoryPool); +GeneralResult unvalidatedConvert( + const hal::V1_3::OptionalTimePoint& optionalTimePoint); +GeneralResult unvalidatedConvert( + const hal::V1_3::OptionalTimeoutDuration& optionalTimeoutDuration); +GeneralResult unvalidatedConvert(const hal::V1_3::ErrorStatus& errorStatus); + GeneralResult convert(const hal::V1_3::Priority& priority); GeneralResult convert(const hal::V1_3::Capabilities& capabilities); -GeneralResult convert( - const hal::V1_3::Capabilities::OperandPerformance& operandPerformance); -GeneralResult convert(const hal::V1_3::Operation& operation); -GeneralResult convert(const hal::V1_3::OperandLifeTime& operandLifeTime); -GeneralResult convert(const hal::V1_3::Operand& operand); GeneralResult convert(const hal::V1_3::Model& model); -GeneralResult convert(const hal::V1_3::Subgraph& subgraph); GeneralResult convert(const hal::V1_3::BufferDesc& bufferDesc); -GeneralResult convert(const hal::V1_3::BufferRole& bufferRole); GeneralResult convert(const hal::V1_3::Request& request); -GeneralResult convert(const hal::V1_3::Request::MemoryPool& memoryPool); GeneralResult convert(const hal::V1_3::OptionalTimePoint& optionalTimePoint); GeneralResult convert( const hal::V1_3::OptionalTimeoutDuration& optionalTimeoutDuration); 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_vec& bufferRoles); @@ -52,26 +67,40 @@ GeneralResult> convert( namespace android::hardware::neuralnetworks::V1_3::utils { -nn::GeneralResult convert(const nn::OperandType& operandType); -nn::GeneralResult convert(const nn::OperationType& operationType); +nn::GeneralResult unvalidatedConvert(const nn::OperandType& operandType); +nn::GeneralResult unvalidatedConvert(const nn::OperationType& operationType); +nn::GeneralResult unvalidatedConvert(const nn::Priority& priority); +nn::GeneralResult unvalidatedConvert(const nn::Capabilities& capabilities); +nn::GeneralResult unvalidatedConvert( + const nn::Capabilities::OperandPerformance& operandPerformance); +nn::GeneralResult unvalidatedConvert(const nn::Operation& operation); +nn::GeneralResult unvalidatedConvert(const nn::Operand::LifeTime& operandLifeTime); +nn::GeneralResult unvalidatedConvert(const nn::Operand& operand); +nn::GeneralResult unvalidatedConvert(const nn::Model& model); +nn::GeneralResult unvalidatedConvert(const nn::Model::Subgraph& subgraph); +nn::GeneralResult unvalidatedConvert(const nn::BufferDesc& bufferDesc); +nn::GeneralResult unvalidatedConvert(const nn::BufferRole& bufferRole); +nn::GeneralResult unvalidatedConvert(const nn::Request& request); +nn::GeneralResult unvalidatedConvert( + const nn::Request::MemoryPool& memoryPool); +nn::GeneralResult unvalidatedConvert( + const nn::OptionalTimePoint& optionalTimePoint); +nn::GeneralResult unvalidatedConvert( + const nn::OptionalTimeoutDuration& optionalTimeoutDuration); +nn::GeneralResult unvalidatedConvert(const nn::ErrorStatus& errorStatus); + nn::GeneralResult convert(const nn::Priority& priority); nn::GeneralResult convert(const nn::Capabilities& capabilities); -nn::GeneralResult convert( - const nn::Capabilities::OperandPerformance& operandPerformance); -nn::GeneralResult convert(const nn::Operation& operation); -nn::GeneralResult convert(const nn::Operand::LifeTime& operandLifeTime); -nn::GeneralResult convert(const nn::Operand& operand); nn::GeneralResult convert(const nn::Model& model); -nn::GeneralResult convert(const nn::Model::Subgraph& subgraph); nn::GeneralResult convert(const nn::BufferDesc& bufferDesc); -nn::GeneralResult convert(const nn::BufferRole& bufferRole); nn::GeneralResult convert(const nn::Request& request); -nn::GeneralResult convert(const nn::Request::MemoryPool& memoryPool); nn::GeneralResult convert(const nn::OptionalTimePoint& optionalTimePoint); nn::GeneralResult convert( const nn::OptionalTimeoutDuration& optionalTimeoutDuration); 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 std::vector& bufferRoles); } // namespace android::hardware::neuralnetworks::V1_3::utils diff --git a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h index e61859d5f9..29b0c806ff 100644 --- a/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h +++ b/neuralnetworks/1.3/utils/include/nnapi/hal/1.3/Utils.h @@ -22,9 +22,7 @@ #include #include #include -#include #include -#include #include #include #include @@ -32,7 +30,6 @@ namespace android::hardware::neuralnetworks::V1_3::utils { constexpr auto kDefaultPriority = Priority::MEDIUM; -constexpr auto kVersion = nn::Version::ANDROID_R; template nn::Result validate(const Type& halObject) { @@ -40,11 +37,6 @@ nn::Result validate(const Type& halObject) { if (!maybeCanonical.has_value()) { return nn::error() << maybeCanonical.error().message; } - const auto version = NN_TRY(nn::validate(maybeCanonical.value())); - if (version > utils::kVersion) { - return NN_ERROR() << "Insufficient version: " << version << " vs required " - << utils::kVersion; - } return {}; } @@ -57,21 +49,6 @@ bool valid(const Type& halObject) { return result.has_value(); } -template -decltype(nn::convert(std::declval())) validatedConvertToCanonical(const Type& halObject) { - auto canonical = NN_TRY(nn::convert(halObject)); - const auto maybeVersion = nn::validate(canonical); - if (!maybeVersion.has_value()) { - return nn::error() << maybeVersion.error(); - } - const auto version = maybeVersion.value(); - if (version > utils::kVersion) { - return NN_ERROR() << "Insufficient version: " << version << " vs required " - << utils::kVersion; - } - return canonical; -} - } // namespace android::hardware::neuralnetworks::V1_3::utils #endif // ANDROID_HARDWARE_INTERFACES_NEURALNETWORKS_1_3_UTILS_H diff --git a/neuralnetworks/1.3/utils/src/Buffer.cpp b/neuralnetworks/1.3/utils/src/Buffer.cpp index f3fe9b5112..a880031ad7 100644 --- a/neuralnetworks/1.3/utils/src/Buffer.cpp +++ b/neuralnetworks/1.3/utils/src/Buffer.cpp @@ -61,13 +61,12 @@ nn::Request::MemoryDomainToken Buffer::getToken() const { } nn::GeneralResult Buffer::copyTo(const nn::Memory& dst) const { - const auto hidlDst = NN_TRY(V1_0::utils::convert(dst)); + const auto hidlDst = NN_TRY(convert(dst)); const auto ret = kBuffer->copyTo(hidlDst); const auto status = NN_TRY(hal::utils::handleTransportError(ret)); if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); return NN_ERROR(canonical) << "IBuffer::copyTo failed with " << toString(status); } @@ -76,14 +75,13 @@ nn::GeneralResult Buffer::copyTo(const nn::Memory& dst) const { nn::GeneralResult Buffer::copyFrom(const nn::Memory& src, const nn::Dimensions& dimensions) const { - const auto hidlSrc = NN_TRY(V1_0::utils::convert(src)); + const auto hidlSrc = NN_TRY(convert(src)); const auto hidlDimensions = hidl_vec(dimensions); const auto ret = kBuffer->copyFrom(hidlSrc, hidlDimensions); const auto status = NN_TRY(hal::utils::handleTransportError(ret)); if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); return NN_ERROR(canonical) << "IBuffer::copyFrom failed with " << toString(status); } diff --git a/neuralnetworks/1.3/utils/src/Callbacks.cpp b/neuralnetworks/1.3/utils/src/Callbacks.cpp index ff81275335..e3c6074549 100644 --- a/neuralnetworks/1.3/utils/src/Callbacks.cpp +++ b/neuralnetworks/1.3/utils/src/Callbacks.cpp @@ -60,8 +60,7 @@ nn::GeneralResult convertPreparedModel( nn::GeneralResult, nn::Timing>> convertExecutionGeneralResultsHelper(const hidl_vec& outputShapes, const V1_2::Timing& timing) { - return std::make_pair(NN_TRY(validatedConvertToCanonical(outputShapes)), - NN_TRY(validatedConvertToCanonical(timing))); + return std::make_pair(NN_TRY(nn::convert(outputShapes)), NN_TRY(nn::convert(timing))); } nn::ExecutionResult, nn::Timing>> @@ -76,8 +75,7 @@ convertExecutionGeneralResults(const hidl_vec& outputShapes, Return PreparedModelCallback::notify(V1_0::ErrorStatus status, const sp& preparedModel) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status)); } else if (preparedModel == nullptr) { notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) @@ -91,8 +89,7 @@ Return PreparedModelCallback::notify(V1_0::ErrorStatus status, Return PreparedModelCallback::notify_1_2(V1_0::ErrorStatus status, const sp& preparedModel) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status)); } else if (preparedModel == nullptr) { notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) @@ -106,8 +103,7 @@ Return PreparedModelCallback::notify_1_2(V1_0::ErrorStatus status, Return PreparedModelCallback::notify_1_3(ErrorStatus status, const sp& preparedModel) { if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); notifyInternal(NN_ERROR(canonical) << "preparedModel failed with " << toString(status)); } else if (preparedModel == nullptr) { notifyInternal(NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) @@ -134,8 +130,7 @@ void PreparedModelCallback::notifyInternal(PreparedModelCallback::Data result) { Return ExecutionCallback::notify(V1_0::ErrorStatus status) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status)); } else { notifyInternal({}); @@ -147,8 +142,7 @@ Return ExecutionCallback::notify_1_2(V1_0::ErrorStatus status, const hidl_vec& outputShapes, const V1_2::Timing& timing) { if (status != V1_0::ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status)); } else { notifyInternal(convertExecutionGeneralResults(outputShapes, timing)); @@ -160,8 +154,7 @@ Return ExecutionCallback::notify_1_3(ErrorStatus status, const hidl_vec& outputShapes, const V1_2::Timing& timing) { if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); notifyInternal(NN_ERROR(canonical) << "execute failed with " << toString(status)); } else { notifyInternal(convertExecutionGeneralResults(outputShapes, timing)); diff --git a/neuralnetworks/1.3/utils/src/Conversions.cpp b/neuralnetworks/1.3/utils/src/Conversions.cpp index 0dc078534c..949dd0d1ed 100644 --- a/neuralnetworks/1.3/utils/src/Conversions.cpp +++ b/neuralnetworks/1.3/utils/src/Conversions.cpp @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -44,6 +45,8 @@ constexpr std::underlying_type_t underlyingType(Type value) { return static_cast>(value); } +constexpr auto kVersion = android::nn::Version::ANDROID_R; + } // namespace namespace android::nn { @@ -77,110 +80,140 @@ constexpr auto validOperandType(nn::OperandType operandType) { using hardware::hidl_vec; template -using ConvertOutput = std::decay_t()).value())>; +using unvalidatedConvertOutput = + std::decay_t()).value())>; template -GeneralResult>> convertVec(const hidl_vec& arguments) { - std::vector> canonical; +GeneralResult>> unvalidatedConvertVec( + const hidl_vec& arguments) { + std::vector> canonical; canonical.reserve(arguments.size()); for (const auto& argument : arguments) { - canonical.push_back(NN_TRY(nn::convert(argument))); + canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument))); } return canonical; } template -GeneralResult>> convert(const hidl_vec& arguments) { - return convertVec(arguments); +GeneralResult>> unvalidatedConvert( + const hidl_vec& arguments) { + return unvalidatedConvertVec(arguments); +} + +template +decltype(nn::unvalidatedConvert(std::declval())) validatedConvert(const Type& halObject) { + auto canonical = NN_TRY(nn::unvalidatedConvert(halObject)); + const auto maybeVersion = validate(canonical); + if (!maybeVersion.has_value()) { + return error() << maybeVersion.error(); + } + const auto version = maybeVersion.value(); + if (version > kVersion) { + return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion; + } + return canonical; +} + +template +GeneralResult>> validatedConvert( + const hidl_vec& arguments) { + std::vector> canonical; + canonical.reserve(arguments.size()); + for (const auto& argument : arguments) { + canonical.push_back(NN_TRY(validatedConvert(argument))); + } + return canonical; } } // anonymous namespace -GeneralResult convert(const hal::V1_3::OperandType& operandType) { +GeneralResult unvalidatedConvert(const hal::V1_3::OperandType& operandType) { return static_cast(operandType); } -GeneralResult convert(const hal::V1_3::OperationType& operationType) { +GeneralResult unvalidatedConvert(const hal::V1_3::OperationType& operationType) { return static_cast(operationType); } -GeneralResult convert(const hal::V1_3::Priority& priority) { +GeneralResult unvalidatedConvert(const hal::V1_3::Priority& priority) { return static_cast(priority); } -GeneralResult convert(const hal::V1_3::Capabilities& capabilities) { +GeneralResult unvalidatedConvert(const hal::V1_3::Capabilities& capabilities) { const bool validOperandTypes = std::all_of( capabilities.operandPerformance.begin(), capabilities.operandPerformance.end(), [](const hal::V1_3::Capabilities::OperandPerformance& operandPerformance) { - const auto maybeType = convert(operandPerformance.type); + const auto maybeType = unvalidatedConvert(operandPerformance.type); return !maybeType.has_value() ? false : validOperandType(maybeType.value()); }); if (!validOperandTypes) { return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) - << "Invalid OperandType when converting OperandPerformance in Capabilities"; + << "Invalid OperandType when unvalidatedConverting OperandPerformance in " + "Capabilities"; } - auto operandPerformance = NN_TRY(convert(capabilities.operandPerformance)); + auto operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance)); auto table = NN_TRY(hal::utils::makeGeneralFailure( Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)), nn::ErrorStatus::GENERAL_FAILURE)); return Capabilities{ - .relaxedFloat32toFloat16PerformanceScalar = - NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceScalar)), - .relaxedFloat32toFloat16PerformanceTensor = - NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor)), + .relaxedFloat32toFloat16PerformanceScalar = NN_TRY( + unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)), + .relaxedFloat32toFloat16PerformanceTensor = NN_TRY( + unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)), .operandPerformance = std::move(table), - .ifPerformance = NN_TRY(convert(capabilities.ifPerformance)), - .whilePerformance = NN_TRY(convert(capabilities.whilePerformance)), + .ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance)), + .whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance)), }; } -GeneralResult convert( +GeneralResult unvalidatedConvert( const hal::V1_3::Capabilities::OperandPerformance& operandPerformance) { return Capabilities::OperandPerformance{ - .type = NN_TRY(convert(operandPerformance.type)), - .info = NN_TRY(convert(operandPerformance.info)), + .type = NN_TRY(unvalidatedConvert(operandPerformance.type)), + .info = NN_TRY(unvalidatedConvert(operandPerformance.info)), }; } -GeneralResult convert(const hal::V1_3::Operation& operation) { +GeneralResult unvalidatedConvert(const hal::V1_3::Operation& operation) { return Operation{ - .type = NN_TRY(convert(operation.type)), + .type = NN_TRY(unvalidatedConvert(operation.type)), .inputs = operation.inputs, .outputs = operation.outputs, }; } -GeneralResult convert(const hal::V1_3::OperandLifeTime& operandLifeTime) { +GeneralResult unvalidatedConvert( + const hal::V1_3::OperandLifeTime& operandLifeTime) { return static_cast(operandLifeTime); } -GeneralResult convert(const hal::V1_3::Operand& operand) { +GeneralResult unvalidatedConvert(const hal::V1_3::Operand& operand) { return Operand{ - .type = NN_TRY(convert(operand.type)), + .type = NN_TRY(unvalidatedConvert(operand.type)), .dimensions = operand.dimensions, .scale = operand.scale, .zeroPoint = operand.zeroPoint, - .lifetime = NN_TRY(convert(operand.lifetime)), - .location = NN_TRY(convert(operand.location)), - .extraParams = NN_TRY(convert(operand.extraParams)), + .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)), + .location = NN_TRY(unvalidatedConvert(operand.location)), + .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)), }; } -GeneralResult convert(const hal::V1_3::Model& model) { +GeneralResult unvalidatedConvert(const hal::V1_3::Model& model) { return Model{ - .main = NN_TRY(convert(model.main)), - .referenced = NN_TRY(convert(model.referenced)), - .operandValues = NN_TRY(convert(model.operandValues)), - .pools = NN_TRY(convert(model.pools)), + .main = NN_TRY(unvalidatedConvert(model.main)), + .referenced = NN_TRY(unvalidatedConvert(model.referenced)), + .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)), + .pools = NN_TRY(unvalidatedConvert(model.pools)), .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16, - .extensionNameToPrefix = NN_TRY(convert(model.extensionNameToPrefix)), + .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)), }; } -GeneralResult convert(const hal::V1_3::Subgraph& subgraph) { - auto operations = NN_TRY(convert(subgraph.operations)); +GeneralResult unvalidatedConvert(const hal::V1_3::Subgraph& subgraph) { + auto operations = NN_TRY(unvalidatedConvert(subgraph.operations)); // Verify number of consumers. const auto numberOfConsumers = @@ -196,18 +229,18 @@ GeneralResult convert(const hal::V1_3::Subgraph& subgraph) { } return Model::Subgraph{ - .operands = NN_TRY(convert(subgraph.operands)), + .operands = NN_TRY(unvalidatedConvert(subgraph.operands)), .operations = std::move(operations), .inputIndexes = subgraph.inputIndexes, .outputIndexes = subgraph.outputIndexes, }; } -GeneralResult convert(const hal::V1_3::BufferDesc& bufferDesc) { +GeneralResult unvalidatedConvert(const hal::V1_3::BufferDesc& bufferDesc) { return BufferDesc{.dimensions = bufferDesc.dimensions}; } -GeneralResult convert(const hal::V1_3::BufferRole& bufferRole) { +GeneralResult unvalidatedConvert(const hal::V1_3::BufferRole& bufferRole) { return BufferRole{ .modelIndex = bufferRole.modelIndex, .ioIndex = bufferRole.ioIndex, @@ -215,15 +248,16 @@ GeneralResult convert(const hal::V1_3::BufferRole& bufferRole) { }; } -GeneralResult convert(const hal::V1_3::Request& request) { +GeneralResult unvalidatedConvert(const hal::V1_3::Request& request) { return Request{ - .inputs = NN_TRY(convert(request.inputs)), - .outputs = NN_TRY(convert(request.outputs)), - .pools = NN_TRY(convert(request.pools)), + .inputs = NN_TRY(unvalidatedConvert(request.inputs)), + .outputs = NN_TRY(unvalidatedConvert(request.outputs)), + .pools = NN_TRY(unvalidatedConvert(request.pools)), }; } -GeneralResult convert(const hal::V1_3::Request::MemoryPool& memoryPool) { +GeneralResult unvalidatedConvert( + const hal::V1_3::Request::MemoryPool& memoryPool) { using Discriminator = hal::V1_3::Request::MemoryPool::hidl_discriminator; switch (memoryPool.getDiscriminator()) { case Discriminator::hidlMemory: @@ -236,12 +270,14 @@ GeneralResult convert(const hal::V1_3::Request::MemoryPool& << underlyingType(memoryPool.getDiscriminator()); } -GeneralResult convert(const hal::V1_3::OptionalTimePoint& optionalTimePoint) { +GeneralResult unvalidatedConvert( + const hal::V1_3::OptionalTimePoint& optionalTimePoint) { constexpr auto kTimePointMaxCount = TimePoint::max().time_since_epoch().count(); const auto makeTimePoint = [](uint64_t count) -> GeneralResult { if (count > kTimePointMaxCount) { return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) - << "Unable to convert OptionalTimePoint because the count exceeds the max"; + << "Unable to unvalidatedConvert OptionalTimePoint because the count exceeds " + "the max"; } const auto nanoseconds = std::chrono::nanoseconds{count}; return TimePoint{nanoseconds}; @@ -259,13 +295,14 @@ GeneralResult convert(const hal::V1_3::OptionalTimePoint& opt << underlyingType(optionalTimePoint.getDiscriminator()); } -GeneralResult convert( +GeneralResult unvalidatedConvert( const hal::V1_3::OptionalTimeoutDuration& optionalTimeoutDuration) { constexpr auto kTimeoutDurationMaxCount = TimeoutDuration::max().count(); const auto makeTimeoutDuration = [](uint64_t count) -> GeneralResult { if (count > kTimeoutDurationMaxCount) { return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) - << "Unable to convert OptionalTimeoutDuration because the count exceeds the max"; + << "Unable to unvalidatedConvert OptionalTimeoutDuration because the count " + "exceeds the max"; } return TimeoutDuration{count}; }; @@ -282,7 +319,7 @@ GeneralResult convert( << underlyingType(optionalTimeoutDuration.getDiscriminator()); } -GeneralResult convert(const hal::V1_3::ErrorStatus& status) { +GeneralResult unvalidatedConvert(const hal::V1_3::ErrorStatus& status) { switch (status) { case hal::V1_3::ErrorStatus::NONE: case hal::V1_3::ErrorStatus::DEVICE_UNAVAILABLE: @@ -299,9 +336,50 @@ GeneralResult convert(const hal::V1_3::ErrorStatus& status) { << "Invalid ErrorStatus " << underlyingType(status); } +GeneralResult convert(const hal::V1_3::Priority& priority) { + return validatedConvert(priority); +} + +GeneralResult convert(const hal::V1_3::Capabilities& capabilities) { + return validatedConvert(capabilities); +} + +GeneralResult convert(const hal::V1_3::Model& model) { + return validatedConvert(model); +} + +GeneralResult convert(const hal::V1_3::BufferDesc& bufferDesc) { + return validatedConvert(bufferDesc); +} + +GeneralResult convert(const hal::V1_3::Request& request) { + return validatedConvert(request); +} + +GeneralResult convert(const hal::V1_3::OptionalTimePoint& optionalTimePoint) { + return validatedConvert(optionalTimePoint); +} + +GeneralResult convert( + const hal::V1_3::OptionalTimeoutDuration& optionalTimeoutDuration) { + return validatedConvert(optionalTimeoutDuration); +} + +GeneralResult convert(const hal::V1_3::ErrorStatus& errorStatus) { + return validatedConvert(errorStatus); +} + +GeneralResult convert(const hardware::hidl_handle& handle) { + return validatedConvert(handle); +} + +GeneralResult convert(const hardware::hidl_memory& memory) { + return validatedConvert(memory); +} + GeneralResult> convert( const hardware::hidl_vec& bufferRoles) { - return convertVec(bufferRoles); + return validatedConvert(bufferRoles); } } // namespace android::nn @@ -309,58 +387,67 @@ GeneralResult> convert( namespace android::hardware::neuralnetworks::V1_3::utils { namespace { -using utils::convert; +using utils::unvalidatedConvert; -nn::GeneralResult convert( +nn::GeneralResult unvalidatedConvert( const nn::Capabilities::PerformanceInfo& performanceInfo) { - return V1_0::utils::convert(performanceInfo); + return V1_0::utils::unvalidatedConvert(performanceInfo); } -nn::GeneralResult convert(const nn::DataLocation& dataLocation) { - return V1_0::utils::convert(dataLocation); +nn::GeneralResult unvalidatedConvert(const nn::DataLocation& dataLocation) { + return V1_0::utils::unvalidatedConvert(dataLocation); } -nn::GeneralResult> convert(const nn::Model::OperandValues& operandValues) { - return V1_0::utils::convert(operandValues); +nn::GeneralResult> unvalidatedConvert( + const nn::Model::OperandValues& operandValues) { + return V1_0::utils::unvalidatedConvert(operandValues); } -nn::GeneralResult convert(const nn::Memory& memory) { - return V1_0::utils::convert(memory); +nn::GeneralResult unvalidatedConvert(const nn::SharedHandle& handle) { + return V1_2::utils::unvalidatedConvert(handle); } -nn::GeneralResult convert(const nn::Request::Argument& argument) { - return V1_0::utils::convert(argument); +nn::GeneralResult unvalidatedConvert(const nn::Memory& memory) { + return V1_0::utils::unvalidatedConvert(memory); } -nn::GeneralResult convert(const nn::Operand::ExtraParams& extraParams) { - return V1_2::utils::convert(extraParams); +nn::GeneralResult unvalidatedConvert(const nn::Request::Argument& argument) { + return V1_0::utils::unvalidatedConvert(argument); } -nn::GeneralResult convert( +nn::GeneralResult unvalidatedConvert( + const nn::Operand::ExtraParams& extraParams) { + return V1_2::utils::unvalidatedConvert(extraParams); +} + +nn::GeneralResult unvalidatedConvert( const nn::Model::ExtensionNameAndPrefix& extensionNameAndPrefix) { - return V1_2::utils::convert(extensionNameAndPrefix); + return V1_2::utils::unvalidatedConvert(extensionNameAndPrefix); } template -using ConvertOutput = std::decay_t()).value())>; +using unvalidatedConvertOutput = + std::decay_t()).value())>; template -nn::GeneralResult>> convertVec(const std::vector& arguments) { - hidl_vec> halObject(arguments.size()); +nn::GeneralResult>> unvalidatedConvertVec( + const std::vector& arguments) { + hidl_vec> halObject(arguments.size()); for (size_t i = 0; i < arguments.size(); ++i) { - halObject[i] = NN_TRY(convert(arguments[i])); + halObject[i] = NN_TRY(unvalidatedConvert(arguments[i])); } return halObject; } template -nn::GeneralResult>> convert(const std::vector& arguments) { - return convertVec(arguments); +nn::GeneralResult>> unvalidatedConvert( + const std::vector& arguments) { + return unvalidatedConvertVec(arguments); } nn::GeneralResult makeMemoryPool(const nn::Memory& memory) { Request::MemoryPool ret; - ret.hidlMemory(NN_TRY(convert(memory))); + ret.hidlMemory(NN_TRY(unvalidatedConvert(memory))); return ret; } @@ -374,21 +461,46 @@ nn::GeneralResult makeMemoryPool(const nn::SharedBuffer& /* return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Unable to make memory pool from IBuffer"; } +using utils::unvalidatedConvert; + +template +decltype(unvalidatedConvert(std::declval())) validatedConvert(const Type& canonical) { + const auto maybeVersion = nn::validate(canonical); + if (!maybeVersion.has_value()) { + return nn::error() << maybeVersion.error(); + } + const auto version = maybeVersion.value(); + if (version > kVersion) { + return NN_ERROR() << "Insufficient version: " << version << " vs required " << kVersion; + } + return unvalidatedConvert(canonical); +} + +template +nn::GeneralResult>> validatedConvert( + const std::vector& arguments) { + hidl_vec> halObject(arguments.size()); + for (size_t i = 0; i < arguments.size(); ++i) { + halObject[i] = NN_TRY(validatedConvert(arguments[i])); + } + return halObject; +} + } // anonymous namespace -nn::GeneralResult convert(const nn::OperandType& operandType) { +nn::GeneralResult unvalidatedConvert(const nn::OperandType& operandType) { return static_cast(operandType); } -nn::GeneralResult convert(const nn::OperationType& operationType) { +nn::GeneralResult unvalidatedConvert(const nn::OperationType& operationType) { return static_cast(operationType); } -nn::GeneralResult convert(const nn::Priority& priority) { +nn::GeneralResult unvalidatedConvert(const nn::Priority& priority) { return static_cast(priority); } -nn::GeneralResult convert(const nn::Capabilities& capabilities) { +nn::GeneralResult unvalidatedConvert(const nn::Capabilities& capabilities) { std::vector operandPerformance; operandPerformance.reserve(capabilities.operandPerformance.asVector().size()); std::copy_if(capabilities.operandPerformance.asVector().begin(), @@ -399,71 +511,72 @@ nn::GeneralResult convert(const nn::Capabilities& capabilities) { }); return Capabilities{ - .relaxedFloat32toFloat16PerformanceScalar = - NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceScalar)), - .relaxedFloat32toFloat16PerformanceTensor = - NN_TRY(convert(capabilities.relaxedFloat32toFloat16PerformanceTensor)), - .operandPerformance = NN_TRY(convert(operandPerformance)), - .ifPerformance = NN_TRY(convert(capabilities.ifPerformance)), - .whilePerformance = NN_TRY(convert(capabilities.whilePerformance)), + .relaxedFloat32toFloat16PerformanceScalar = NN_TRY( + unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)), + .relaxedFloat32toFloat16PerformanceTensor = NN_TRY( + unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)), + .operandPerformance = NN_TRY(unvalidatedConvert(operandPerformance)), + .ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance)), + .whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance)), }; } -nn::GeneralResult convert( +nn::GeneralResult unvalidatedConvert( const nn::Capabilities::OperandPerformance& operandPerformance) { return Capabilities::OperandPerformance{ - .type = NN_TRY(convert(operandPerformance.type)), - .info = NN_TRY(convert(operandPerformance.info)), + .type = NN_TRY(unvalidatedConvert(operandPerformance.type)), + .info = NN_TRY(unvalidatedConvert(operandPerformance.info)), }; } -nn::GeneralResult convert(const nn::Operation& operation) { +nn::GeneralResult unvalidatedConvert(const nn::Operation& operation) { return Operation{ - .type = NN_TRY(convert(operation.type)), + .type = NN_TRY(unvalidatedConvert(operation.type)), .inputs = operation.inputs, .outputs = operation.outputs, }; } -nn::GeneralResult convert(const nn::Operand::LifeTime& operandLifeTime) { +nn::GeneralResult unvalidatedConvert( + const nn::Operand::LifeTime& operandLifeTime) { if (operandLifeTime == nn::Operand::LifeTime::POINTER) { return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) - << "Model cannot be converted because it contains pointer-based memory"; + << "Model cannot be unvalidatedConverted because it contains pointer-based memory"; } return static_cast(operandLifeTime); } -nn::GeneralResult convert(const nn::Operand& operand) { +nn::GeneralResult unvalidatedConvert(const nn::Operand& operand) { return Operand{ - .type = NN_TRY(convert(operand.type)), + .type = NN_TRY(unvalidatedConvert(operand.type)), .dimensions = operand.dimensions, .numberOfConsumers = 0, .scale = operand.scale, .zeroPoint = operand.zeroPoint, - .lifetime = NN_TRY(convert(operand.lifetime)), - .location = NN_TRY(convert(operand.location)), - .extraParams = NN_TRY(convert(operand.extraParams)), + .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)), + .location = NN_TRY(unvalidatedConvert(operand.location)), + .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)), }; } -nn::GeneralResult convert(const nn::Model& model) { +nn::GeneralResult unvalidatedConvert(const nn::Model& model) { if (!hal::utils::hasNoPointerData(model)) { return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) - << "Model cannot be converted because it contains pointer-based memory"; + << "Model cannot be unvalidatedConverted because it contains pointer-based memory"; } return Model{ - .main = NN_TRY(convert(model.main)), - .referenced = NN_TRY(convert(model.referenced)), - .operandValues = NN_TRY(convert(model.operandValues)), - .pools = NN_TRY(convert(model.pools)), + .main = NN_TRY(unvalidatedConvert(model.main)), + .referenced = NN_TRY(unvalidatedConvert(model.referenced)), + .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)), + .pools = NN_TRY(unvalidatedConvert(model.pools)), .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16, - .extensionNameToPrefix = NN_TRY(convert(model.extensionNameToPrefix)), + .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)), }; } -nn::GeneralResult convert(const nn::Model::Subgraph& subgraph) { - auto operands = NN_TRY(convert(subgraph.operands)); +nn::GeneralResult unvalidatedConvert(const nn::Model::Subgraph& subgraph) { + auto operands = NN_TRY(unvalidatedConvert(subgraph.operands)); // Update number of consumers. const auto numberOfConsumers = @@ -475,17 +588,17 @@ nn::GeneralResult convert(const nn::Model::Subgraph& subgraph) { return Subgraph{ .operands = std::move(operands), - .operations = NN_TRY(convert(subgraph.operations)), + .operations = NN_TRY(unvalidatedConvert(subgraph.operations)), .inputIndexes = subgraph.inputIndexes, .outputIndexes = subgraph.outputIndexes, }; } -nn::GeneralResult convert(const nn::BufferDesc& bufferDesc) { +nn::GeneralResult unvalidatedConvert(const nn::BufferDesc& bufferDesc) { return BufferDesc{.dimensions = bufferDesc.dimensions}; } -nn::GeneralResult convert(const nn::BufferRole& bufferRole) { +nn::GeneralResult unvalidatedConvert(const nn::BufferRole& bufferRole) { return BufferRole{ .modelIndex = bufferRole.modelIndex, .ioIndex = bufferRole.ioIndex, @@ -493,30 +606,33 @@ nn::GeneralResult convert(const nn::BufferRole& bufferRole) { }; } -nn::GeneralResult convert(const nn::Request& request) { +nn::GeneralResult unvalidatedConvert(const nn::Request& request) { if (!hal::utils::hasNoPointerData(request)) { return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) - << "Request cannot be converted because it contains pointer-based memory"; + << "Request cannot be unvalidatedConverted because it contains pointer-based memory"; } return Request{ - .inputs = NN_TRY(convert(request.inputs)), - .outputs = NN_TRY(convert(request.outputs)), - .pools = NN_TRY(convert(request.pools)), + .inputs = NN_TRY(unvalidatedConvert(request.inputs)), + .outputs = NN_TRY(unvalidatedConvert(request.outputs)), + .pools = NN_TRY(unvalidatedConvert(request.pools)), }; } -nn::GeneralResult convert(const nn::Request::MemoryPool& memoryPool) { +nn::GeneralResult unvalidatedConvert( + const nn::Request::MemoryPool& memoryPool) { return std::visit([](const auto& o) { return makeMemoryPool(o); }, memoryPool); } -nn::GeneralResult convert(const nn::OptionalTimePoint& optionalTimePoint) { +nn::GeneralResult unvalidatedConvert( + const nn::OptionalTimePoint& optionalTimePoint) { OptionalTimePoint ret; if (optionalTimePoint.has_value()) { const auto count = optionalTimePoint.value().time_since_epoch().count(); if (count < 0) { return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) - << "Unable to convert OptionalTimePoint because time since epoch count is " + << "Unable to unvalidatedConvert OptionalTimePoint because time since epoch " + "count is " "negative"; } ret.nanosecondsSinceEpoch(count); @@ -524,21 +640,22 @@ nn::GeneralResult convert(const nn::OptionalTimePoint& option return ret; } -nn::GeneralResult convert( +nn::GeneralResult unvalidatedConvert( const nn::OptionalTimeoutDuration& optionalTimeoutDuration) { OptionalTimeoutDuration ret; if (optionalTimeoutDuration.has_value()) { const auto count = optionalTimeoutDuration.value().count(); if (count < 0) { return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) - << "Unable to convert OptionalTimeoutDuration because count is negative"; + << "Unable to unvalidatedConvert OptionalTimeoutDuration because count is " + "negative"; } ret.nanoseconds(count); } return ret; } -nn::GeneralResult convert(const nn::ErrorStatus& errorStatus) { +nn::GeneralResult unvalidatedConvert(const nn::ErrorStatus& errorStatus) { switch (errorStatus) { case nn::ErrorStatus::NONE: case nn::ErrorStatus::DEVICE_UNAVAILABLE: @@ -555,8 +672,49 @@ nn::GeneralResult convert(const nn::ErrorStatus& errorStatus) { } } +nn::GeneralResult convert(const nn::Priority& priority) { + return validatedConvert(priority); +} + +nn::GeneralResult convert(const nn::Capabilities& capabilities) { + return validatedConvert(capabilities); +} + +nn::GeneralResult convert(const nn::Model& model) { + return validatedConvert(model); +} + +nn::GeneralResult convert(const nn::BufferDesc& bufferDesc) { + return validatedConvert(bufferDesc); +} + +nn::GeneralResult convert(const nn::Request& request) { + return validatedConvert(request); +} + +nn::GeneralResult convert(const nn::OptionalTimePoint& optionalTimePoint) { + return validatedConvert(optionalTimePoint); +} + +nn::GeneralResult convert( + const nn::OptionalTimeoutDuration& optionalTimeoutDuration) { + return validatedConvert(optionalTimeoutDuration); +} + +nn::GeneralResult convert(const nn::ErrorStatus& errorStatus) { + return validatedConvert(errorStatus); +} + +nn::GeneralResult convert(const nn::SharedHandle& handle) { + return validatedConvert(handle); +} + +nn::GeneralResult convert(const nn::Memory& memory) { + return validatedConvert(memory); +} + nn::GeneralResult> convert(const std::vector& bufferRoles) { - return convertVec(bufferRoles); + return validatedConvert(bufferRoles); } } // namespace android::hardware::neuralnetworks::V1_3::utils diff --git a/neuralnetworks/1.3/utils/src/Device.cpp b/neuralnetworks/1.3/utils/src/Device.cpp index 0fa244d891..7a7e2514ef 100644 --- a/neuralnetworks/1.3/utils/src/Device.cpp +++ b/neuralnetworks/1.3/utils/src/Device.cpp @@ -78,11 +78,10 @@ nn::GeneralResult initCapabilities(V1_3::IDevice* device) { << "uninitialized"; const auto cb = [&result](ErrorStatus status, const Capabilities& capabilities) { if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "getCapabilities_1_3 failed with " << toString(status); } else { - result = validatedConvertToCanonical(capabilities); + result = nn::convert(capabilities); } }; @@ -178,8 +177,7 @@ nn::GeneralResult> Device::getSupportedOperations(const nn::Mo << "uninitialized"; auto cb = [&result, &model](ErrorStatus status, const hidl_vec& supportedOperations) { if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "IDevice::getSupportedOperations_1_3 failed with " << toString(status); } else if (supportedOperations.size() != model.main.operations.size()) { @@ -223,8 +221,7 @@ nn::GeneralResult Device::prepareModel( hidlModelCache, hidlDataCache, hidlToken, cb); const auto status = NN_TRY(hal::utils::handleTransportError(ret)); if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); return NN_ERROR(canonical) << "prepareModel_1_3 failed with " << toString(status); } @@ -246,8 +243,7 @@ nn::GeneralResult Device::prepareModelFromCache( hidlToken, cb); const auto status = NN_TRY(hal::utils::handleTransportError(ret)); if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); return NN_ERROR(canonical) << "prepareModelFromCache_1_3 failed with " << toString(status); } @@ -267,8 +263,7 @@ nn::GeneralResult Device::allocate( << "uninitialized"; auto cb = [&result](ErrorStatus status, const sp& buffer, uint32_t token) { if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "IDevice::allocate failed with " << toString(status); } else if (buffer == nullptr) { result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE) << "Returned buffer is nullptr"; diff --git a/neuralnetworks/1.3/utils/src/PreparedModel.cpp b/neuralnetworks/1.3/utils/src/PreparedModel.cpp index 2781053d07..5d82110829 100644 --- a/neuralnetworks/1.3/utils/src/PreparedModel.cpp +++ b/neuralnetworks/1.3/utils/src/PreparedModel.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include @@ -44,8 +45,7 @@ namespace { nn::GeneralResult, nn::Timing>> convertExecutionResultsHelper(const hidl_vec& outputShapes, const V1_2::Timing& timing) { - return std::make_pair(NN_TRY(validatedConvertToCanonical(outputShapes)), - NN_TRY(validatedConvertToCanonical(timing))); + return std::make_pair(NN_TRY(nn::convert(outputShapes)), NN_TRY(nn::convert(timing))); } nn::ExecutionResult, nn::Timing>> convertExecutionResults( @@ -55,8 +55,7 @@ nn::ExecutionResult, nn::Timing>> convert nn::GeneralResult> convertFencedExecutionCallbackResults( const V1_2::Timing& timingLaunched, const V1_2::Timing& timingFenced) { - return std::make_pair(NN_TRY(validatedConvertToCanonical(timingLaunched)), - NN_TRY(validatedConvertToCanonical(timingFenced))); + return std::make_pair(NN_TRY(nn::convert(timingLaunched)), NN_TRY(nn::convert(timingFenced))); } nn::GeneralResult> @@ -64,9 +63,9 @@ convertExecuteFencedResults(const hidl_handle& syncFence, const sp& callback) { auto resultSyncFence = nn::SyncFence::createAsSignaled(); if (syncFence.getNativeHandle() != nullptr) { - auto nativeHandle = NN_TRY(validatedConvertToCanonical(syncFence)); + auto sharedHandle = NN_TRY(nn::convert(syncFence)); resultSyncFence = NN_TRY(hal::utils::makeGeneralFailure( - nn::SyncFence::create(std::move(nativeHandle)), nn::ErrorStatus::GENERAL_FAILURE)); + nn::SyncFence::create(std::move(sharedHandle)), nn::ErrorStatus::GENERAL_FAILURE)); } if (callback == nullptr) { @@ -81,8 +80,8 @@ convertExecuteFencedResults(const hidl_handle& syncFence, auto cb = [&result](ErrorStatus status, const V1_2::Timing& timingLaunched, const V1_2::Timing& timingFenced) { if (status != ErrorStatus::NONE) { - const auto canonical = validatedConvertToCanonical(status).value_or( - nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = + nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "getExecutionInfo failed with " << toString(status); } else { result = convertFencedExecutionCallbackResults(timingLaunched, timingFenced); @@ -125,8 +124,7 @@ PreparedModel::executeSynchronously(const Request& request, V1_2::MeasureTiming const auto cb = [&result](ErrorStatus status, const hidl_vec& outputShapes, const V1_2::Timing& timing) { if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "executeSynchronously failed with " << toString(status); } else { result = convertExecutionResults(outputShapes, timing); @@ -152,8 +150,7 @@ PreparedModel::executeAsynchronously(const Request& request, V1_2::MeasureTiming const auto status = NN_TRY(hal::utils::makeExecutionFailure(hal::utils::handleTransportError(ret))); if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); return NN_ERROR(canonical) << "executeAsynchronously failed with " << toString(status); } @@ -223,8 +220,7 @@ PreparedModel::executeFenced(const nn::Request& request, const std::vector& callback) { if (status != ErrorStatus::NONE) { - const auto canonical = - validatedConvertToCanonical(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); + const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE); result = NN_ERROR(canonical) << "executeFenced failed with " << toString(status); } else { result = convertExecuteFencedResults(syncFence, callback); diff --git a/neuralnetworks/utils/README.md b/neuralnetworks/utils/README.md new file mode 100644 index 0000000000..0dee103811 --- /dev/null +++ b/neuralnetworks/utils/README.md @@ -0,0 +1,50 @@ +# NNAPI Conversions + +`convert` fails if either the source type or the destination type is invalid, and it yields a valid +object if the conversion succeeds. For example, let's say that an enumeration in the current +version has fewer possible values than the "same" canonical enumeration, such as `OperationType`. +The new value of `HARD_SWISH` (introduced in Android R / NN HAL 1.3) does not map to any valid +existing value in `OperationType`, but an older value of `ADD` (introduced in Android OC-MR1 / NN +HAL 1.0) is valid. This can be seen in the following model conversions: + +```cpp +// Unsuccessful conversion +const nn::Model canonicalModel = createModelWhichHasV1_3Operations(); +const nn::Result maybeVersionedModel = V1_0::utils::convert(canonicalModel); +EXPECT_FALSE(maybeVersionedModel.has_value()); +``` +```cpp +// Successful conversion +const nn::Model canonicalModel = createModelWhichHasOnlyV1_0Operations(); +const nn::Result maybeVersionedModel = V1_0::utils::convert(canonicalModel); +ASSERT_TRUE(maybeVersionedModel.has_value()); +const V1_0::Model& versionedModel = maybeVersionedModel.value(); +EXPECT_TRUE(V1_0::utils::valid(versionedModel)); +``` + +`V1_X::utils::convert` does not guarantee that all information is preserved. For example, In the +case of `nn::ErrorStatus`, the new value of `MISSED_DEADLINE_TRANSIENT` can be represented by the +existing value of `V1_0::GENERAL_FAILURE`: + +```cpp +// Lossy Canonical -> HAL -> Canonical conversion +const nn::ErrorStatus canonicalBefore = nn::ErrorStatus::MISSED_DEADLINE_TRANSIENT; +const V1_0::ErrorStatus versioned = V1_0::utils::convert(canonicalBefore).value(); +const nn::ErrorStatus canonicalAfter = nn::convert(versioned).value(); +EXPECT_NE(canonicalBefore, canonicalAfter); +``` + +However, `nn::convert` is guaranteed to preserve all information: + +```cpp +// Lossless HAL -> Canonical -> HAL conversion +const V1_0::ErrorStatus versionedBefore = V1_0::ErrorStatus::GENERAL_FAILURE; +const nn::ErrorStatus canonical = nn::convert(versionedBefore).value(); +const V1_0::ErrorStatus versionedAfter = V1_0::utils::convert(canonical).value(); +EXPECT_EQ(versionedBefore, versionedAfter); +``` + +The `convert` functions operate only on types that used in a HIDL method call directly. The +`unvalidatedConvert` functions operate on types that are either used in a HIDL method call directly +(i.e., not as a nested class) or used in a subsequent version of the NN HAL. Prefer using `convert` +over `unvalidatedConvert`.