blob: 113d2da95591b5b049c34dc8a09f1bcb31d640f0 [file] [log] [blame]
Lev Proleev6b6dfcd2020-11-11 18:28:50 +00001/*
2 * Copyright (C) 2021 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "Conversions.h"
18
Michael Butlerf03ebd92021-03-25 15:27:38 -070019#include <aidl/android/hardware/common/Ashmem.h>
20#include <aidl/android/hardware/common/MappableFile.h>
Lev Proleev6b6dfcd2020-11-11 18:28:50 +000021#include <aidl/android/hardware/common/NativeHandle.h>
Michael Butlerf03ebd92021-03-25 15:27:38 -070022#include <aidl/android/hardware/graphics/common/HardwareBuffer.h>
23#include <aidlcommonsupport/NativeHandle.h>
Lev Proleev6b6dfcd2020-11-11 18:28:50 +000024#include <android-base/logging.h>
Michael Butlerf03ebd92021-03-25 15:27:38 -070025#include <android-base/mapped_file.h>
Lev Proleev900c28a2021-01-26 19:40:20 +000026#include <android-base/unique_fd.h>
27#include <android/binder_auto_utils.h>
Michael Butlerab2f4822021-02-08 00:05:07 -080028#include <cutils/native_handle.h>
Lev Proleev6b6dfcd2020-11-11 18:28:50 +000029#include <nnapi/OperandTypes.h>
30#include <nnapi/OperationTypes.h>
31#include <nnapi/Result.h>
32#include <nnapi/SharedMemory.h>
33#include <nnapi/TypeUtils.h>
34#include <nnapi/Types.h>
35#include <nnapi/Validation.h>
36#include <nnapi/hal/CommonUtils.h>
Lev Proleev6b6dfcd2020-11-11 18:28:50 +000037
38#include <algorithm>
39#include <chrono>
40#include <functional>
41#include <iterator>
42#include <limits>
43#include <type_traits>
44#include <utility>
45
Michael Butler388bceb2021-02-03 15:15:43 -080046#include "Utils.h"
47
Ray Hernandez338d6f82021-08-11 21:29:20 +000048#ifdef __ANDROID__
49#include <android/hardware_buffer.h>
50#include <vndk/hardware_buffer.h>
51#endif // __ANDROID__
52
Lev Proleev6b6dfcd2020-11-11 18:28:50 +000053#define VERIFY_NON_NEGATIVE(value) \
54 while (UNLIKELY(value < 0)) return NN_ERROR()
55
Lev Proleev900c28a2021-01-26 19:40:20 +000056#define VERIFY_LE_INT32_MAX(value) \
57 while (UNLIKELY(value > std::numeric_limits<int32_t>::max())) return NN_ERROR()
Lev Proleev6b6dfcd2020-11-11 18:28:50 +000058
Lev Proleev900c28a2021-01-26 19:40:20 +000059namespace {
Lev Proleev6b6dfcd2020-11-11 18:28:50 +000060template <typename Type>
61constexpr std::underlying_type_t<Type> underlyingType(Type value) {
62 return static_cast<std::underlying_type_t<Type>>(value);
63}
64
Lev Proleev900c28a2021-01-26 19:40:20 +000065constexpr int64_t kNoTiming = -1;
Lev Proleev6b6dfcd2020-11-11 18:28:50 +000066
67} // namespace
68
69namespace android::nn {
70namespace {
71
Michael Butlerfadeb8a2021-02-07 00:11:13 -080072using ::aidl::android::hardware::common::NativeHandle;
73
Lev Proleev6b6dfcd2020-11-11 18:28:50 +000074template <typename Input>
75using UnvalidatedConvertOutput =
76 std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
77
78template <typename Type>
79GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvertVec(
80 const std::vector<Type>& arguments) {
81 std::vector<UnvalidatedConvertOutput<Type>> canonical;
82 canonical.reserve(arguments.size());
83 for (const auto& argument : arguments) {
84 canonical.push_back(NN_TRY(nn::unvalidatedConvert(argument)));
85 }
86 return canonical;
87}
88
89template <typename Type>
90GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
91 const std::vector<Type>& arguments) {
92 return unvalidatedConvertVec(arguments);
93}
94
95template <typename Type>
96GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& halObject) {
97 auto canonical = NN_TRY(nn::unvalidatedConvert(halObject));
Michael Butler388bceb2021-02-03 15:15:43 -080098 NN_TRY(aidl_hal::utils::compliantVersion(canonical));
Lev Proleev6b6dfcd2020-11-11 18:28:50 +000099 return canonical;
100}
101
102template <typename Type>
103GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> validatedConvert(
104 const std::vector<Type>& arguments) {
105 std::vector<UnvalidatedConvertOutput<Type>> canonical;
106 canonical.reserve(arguments.size());
107 for (const auto& argument : arguments) {
108 canonical.push_back(NN_TRY(validatedConvert(argument)));
109 }
110 return canonical;
111}
112
Michael Butlerab2f4822021-02-08 00:05:07 -0800113struct NativeHandleDeleter {
114 void operator()(native_handle_t* handle) const {
115 if (handle) {
116 native_handle_close(handle);
117 native_handle_delete(handle);
118 }
119 }
120};
121
122using UniqueNativeHandle = std::unique_ptr<native_handle_t, NativeHandleDeleter>;
123
Ray Hernandez338d6f82021-08-11 21:29:20 +0000124#ifdef __ANDROID__
Michael Butlerf03ebd92021-03-25 15:27:38 -0700125GeneralResult<UniqueNativeHandle> nativeHandleFromAidlHandle(const NativeHandle& handle) {
126 auto nativeHandle = UniqueNativeHandle(dupFromAidl(handle));
127 if (nativeHandle.get() == nullptr) {
128 return NN_ERROR() << "android::dupFromAidl failed to convert the common::NativeHandle to a "
129 "native_handle_t";
Michael Butlerab2f4822021-02-08 00:05:07 -0800130 }
Michael Butlerf03ebd92021-03-25 15:27:38 -0700131 if (!std::all_of(nativeHandle->data + 0, nativeHandle->data + nativeHandle->numFds,
132 [](int fd) { return fd >= 0; })) {
133 return NN_ERROR() << "android::dupFromAidl returned an invalid native_handle_t";
Michael Butlerab2f4822021-02-08 00:05:07 -0800134 }
Michael Butlerf03ebd92021-03-25 15:27:38 -0700135 return nativeHandle;
Michael Butlerab2f4822021-02-08 00:05:07 -0800136}
Ray Hernandez338d6f82021-08-11 21:29:20 +0000137#endif // __ANDROID__
Michael Butlerab2f4822021-02-08 00:05:07 -0800138
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000139} // anonymous namespace
140
141GeneralResult<OperandType> unvalidatedConvert(const aidl_hal::OperandType& operandType) {
142 VERIFY_NON_NEGATIVE(underlyingType(operandType)) << "Negative operand types are not allowed.";
Michael Butler388bceb2021-02-03 15:15:43 -0800143 const auto canonical = static_cast<OperandType>(operandType);
144 if (canonical == OperandType::OEM || canonical == OperandType::TENSOR_OEM_BYTE) {
145 return NN_ERROR() << "Unable to convert invalid OperandType " << canonical;
146 }
147 return canonical;
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000148}
149
150GeneralResult<OperationType> unvalidatedConvert(const aidl_hal::OperationType& operationType) {
151 VERIFY_NON_NEGATIVE(underlyingType(operationType))
152 << "Negative operation types are not allowed.";
Michael Butler388bceb2021-02-03 15:15:43 -0800153 const auto canonical = static_cast<OperationType>(operationType);
154 if (canonical == OperationType::OEM_OPERATION) {
155 return NN_ERROR() << "Unable to convert invalid OperationType OEM_OPERATION";
156 }
157 return canonical;
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000158}
159
160GeneralResult<DeviceType> unvalidatedConvert(const aidl_hal::DeviceType& deviceType) {
161 return static_cast<DeviceType>(deviceType);
162}
163
164GeneralResult<Priority> unvalidatedConvert(const aidl_hal::Priority& priority) {
165 return static_cast<Priority>(priority);
166}
167
168GeneralResult<Capabilities> unvalidatedConvert(const aidl_hal::Capabilities& capabilities) {
169 const bool validOperandTypes = std::all_of(
170 capabilities.operandPerformance.begin(), capabilities.operandPerformance.end(),
171 [](const aidl_hal::OperandPerformance& operandPerformance) {
Michael Butler388bceb2021-02-03 15:15:43 -0800172 return validatedConvert(operandPerformance.type).has_value();
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000173 });
174 if (!validOperandTypes) {
175 return NN_ERROR() << "Invalid OperandType when unvalidatedConverting OperandPerformance in "
176 "Capabilities";
177 }
178
179 auto operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance));
Michael Butlerff9a5a52021-10-15 16:23:20 -0700180 auto table =
181 NN_TRY(Capabilities::OperandPerformanceTable::create(std::move(operandPerformance)));
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000182
183 return Capabilities{
184 .relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
185 unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
186 .relaxedFloat32toFloat16PerformanceTensor = NN_TRY(
187 unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
188 .operandPerformance = std::move(table),
189 .ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance)),
190 .whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance)),
191 };
192}
193
194GeneralResult<Capabilities::OperandPerformance> unvalidatedConvert(
195 const aidl_hal::OperandPerformance& operandPerformance) {
196 return Capabilities::OperandPerformance{
197 .type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
198 .info = NN_TRY(unvalidatedConvert(operandPerformance.info)),
199 };
200}
201
202GeneralResult<Capabilities::PerformanceInfo> unvalidatedConvert(
203 const aidl_hal::PerformanceInfo& performanceInfo) {
204 return Capabilities::PerformanceInfo{
205 .execTime = performanceInfo.execTime,
206 .powerUsage = performanceInfo.powerUsage,
207 };
208}
209
210GeneralResult<DataLocation> unvalidatedConvert(const aidl_hal::DataLocation& location) {
211 VERIFY_NON_NEGATIVE(location.poolIndex) << "DataLocation: pool index must not be negative";
212 VERIFY_NON_NEGATIVE(location.offset) << "DataLocation: offset must not be negative";
213 VERIFY_NON_NEGATIVE(location.length) << "DataLocation: length must not be negative";
Xusong Wang5e36ca02021-02-16 10:40:32 -0800214 VERIFY_NON_NEGATIVE(location.padding) << "DataLocation: padding must not be negative";
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000215 if (location.offset > std::numeric_limits<uint32_t>::max()) {
216 return NN_ERROR() << "DataLocation: offset must be <= std::numeric_limits<uint32_t>::max()";
217 }
218 if (location.length > std::numeric_limits<uint32_t>::max()) {
219 return NN_ERROR() << "DataLocation: length must be <= std::numeric_limits<uint32_t>::max()";
220 }
Xusong Wang5e36ca02021-02-16 10:40:32 -0800221 if (location.padding > std::numeric_limits<uint32_t>::max()) {
222 return NN_ERROR()
223 << "DataLocation: padding must be <= std::numeric_limits<uint32_t>::max()";
224 }
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000225 return DataLocation{
226 .poolIndex = static_cast<uint32_t>(location.poolIndex),
227 .offset = static_cast<uint32_t>(location.offset),
228 .length = static_cast<uint32_t>(location.length),
Xusong Wang5e36ca02021-02-16 10:40:32 -0800229 .padding = static_cast<uint32_t>(location.padding),
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000230 };
231}
232
233GeneralResult<Operation> unvalidatedConvert(const aidl_hal::Operation& operation) {
234 return Operation{
235 .type = NN_TRY(unvalidatedConvert(operation.type)),
236 .inputs = NN_TRY(toUnsigned(operation.inputs)),
237 .outputs = NN_TRY(toUnsigned(operation.outputs)),
238 };
239}
240
241GeneralResult<Operand::LifeTime> unvalidatedConvert(
242 const aidl_hal::OperandLifeTime& operandLifeTime) {
243 return static_cast<Operand::LifeTime>(operandLifeTime);
244}
245
246GeneralResult<Operand> unvalidatedConvert(const aidl_hal::Operand& operand) {
247 return Operand{
248 .type = NN_TRY(unvalidatedConvert(operand.type)),
249 .dimensions = NN_TRY(toUnsigned(operand.dimensions)),
250 .scale = operand.scale,
251 .zeroPoint = operand.zeroPoint,
252 .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
253 .location = NN_TRY(unvalidatedConvert(operand.location)),
254 .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
255 };
256}
257
258GeneralResult<Operand::ExtraParams> unvalidatedConvert(
259 const std::optional<aidl_hal::OperandExtraParams>& optionalExtraParams) {
260 if (!optionalExtraParams.has_value()) {
261 return Operand::NoParams{};
262 }
263 const auto& extraParams = optionalExtraParams.value();
264 using Tag = aidl_hal::OperandExtraParams::Tag;
265 switch (extraParams.getTag()) {
266 case Tag::channelQuant:
267 return unvalidatedConvert(extraParams.get<Tag::channelQuant>());
268 case Tag::extension:
269 return extraParams.get<Tag::extension>();
270 }
271 return NN_ERROR() << "Unrecognized Operand::ExtraParams tag: "
272 << underlyingType(extraParams.getTag());
273}
274
275GeneralResult<Operand::SymmPerChannelQuantParams> unvalidatedConvert(
276 const aidl_hal::SymmPerChannelQuantParams& symmPerChannelQuantParams) {
277 VERIFY_NON_NEGATIVE(symmPerChannelQuantParams.channelDim)
278 << "Per-channel quantization channel dimension must not be negative.";
279 return Operand::SymmPerChannelQuantParams{
280 .scales = symmPerChannelQuantParams.scales,
281 .channelDim = static_cast<uint32_t>(symmPerChannelQuantParams.channelDim),
282 };
283}
284
285GeneralResult<Model> unvalidatedConvert(const aidl_hal::Model& model) {
286 return Model{
287 .main = NN_TRY(unvalidatedConvert(model.main)),
288 .referenced = NN_TRY(unvalidatedConvert(model.referenced)),
289 .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
290 .pools = NN_TRY(unvalidatedConvert(model.pools)),
291 .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
292 .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
293 };
294}
295
296GeneralResult<Model::Subgraph> unvalidatedConvert(const aidl_hal::Subgraph& subgraph) {
297 return Model::Subgraph{
298 .operands = NN_TRY(unvalidatedConvert(subgraph.operands)),
299 .operations = NN_TRY(unvalidatedConvert(subgraph.operations)),
300 .inputIndexes = NN_TRY(toUnsigned(subgraph.inputIndexes)),
301 .outputIndexes = NN_TRY(toUnsigned(subgraph.outputIndexes)),
302 };
303}
304
305GeneralResult<Model::ExtensionNameAndPrefix> unvalidatedConvert(
306 const aidl_hal::ExtensionNameAndPrefix& extensionNameAndPrefix) {
307 return Model::ExtensionNameAndPrefix{
308 .name = extensionNameAndPrefix.name,
309 .prefix = extensionNameAndPrefix.prefix,
310 };
311}
312
313GeneralResult<Extension> unvalidatedConvert(const aidl_hal::Extension& extension) {
314 return Extension{
315 .name = extension.name,
316 .operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes)),
317 };
318}
319
320GeneralResult<Extension::OperandTypeInformation> unvalidatedConvert(
321 const aidl_hal::ExtensionOperandTypeInformation& operandTypeInformation) {
322 VERIFY_NON_NEGATIVE(operandTypeInformation.byteSize)
323 << "Extension operand type byte size must not be negative";
324 return Extension::OperandTypeInformation{
325 .type = operandTypeInformation.type,
326 .isTensor = operandTypeInformation.isTensor,
327 .byteSize = static_cast<uint32_t>(operandTypeInformation.byteSize),
328 };
329}
330
331GeneralResult<OutputShape> unvalidatedConvert(const aidl_hal::OutputShape& outputShape) {
332 return OutputShape{
333 .dimensions = NN_TRY(toUnsigned(outputShape.dimensions)),
334 .isSufficient = outputShape.isSufficient,
335 };
336}
337
338GeneralResult<MeasureTiming> unvalidatedConvert(bool measureTiming) {
339 return measureTiming ? MeasureTiming::YES : MeasureTiming::NO;
340}
341
Michael Butlerfadeb8a2021-02-07 00:11:13 -0800342GeneralResult<SharedMemory> unvalidatedConvert(const aidl_hal::Memory& memory) {
Michael Butlerf03ebd92021-03-25 15:27:38 -0700343 using Tag = aidl_hal::Memory::Tag;
344 switch (memory.getTag()) {
345 case Tag::ashmem: {
346 const auto& ashmem = memory.get<Tag::ashmem>();
347 VERIFY_NON_NEGATIVE(ashmem.size) << "Memory size must not be negative";
348 if (ashmem.size > std::numeric_limits<size_t>::max()) {
349 return NN_ERROR() << "Memory: size must be <= std::numeric_limits<size_t>::max()";
350 }
Michael Butlerab2f4822021-02-08 00:05:07 -0800351
Michael Butlerf03ebd92021-03-25 15:27:38 -0700352 auto handle = Memory::Ashmem{
353 .fd = NN_TRY(dupFd(ashmem.fd.get())),
354 .size = static_cast<size_t>(ashmem.size),
355 };
356 return std::make_shared<const Memory>(Memory{.handle = std::move(handle)});
357 }
358 case Tag::mappableFile: {
359 const auto& mappableFile = memory.get<Tag::mappableFile>();
360 VERIFY_NON_NEGATIVE(mappableFile.length) << "Memory size must not be negative";
361 VERIFY_NON_NEGATIVE(mappableFile.offset) << "Memory offset must not be negative";
362 if (mappableFile.length > std::numeric_limits<size_t>::max()) {
363 return NN_ERROR() << "Memory: size must be <= std::numeric_limits<size_t>::max()";
364 }
365 if (mappableFile.offset > std::numeric_limits<size_t>::max()) {
366 return NN_ERROR() << "Memory: offset must be <= std::numeric_limits<size_t>::max()";
367 }
Michael Butlerab2f4822021-02-08 00:05:07 -0800368
Michael Butlerf03ebd92021-03-25 15:27:38 -0700369 const size_t size = static_cast<size_t>(mappableFile.length);
370 const int prot = mappableFile.prot;
371 const int fd = mappableFile.fd.get();
372 const size_t offset = static_cast<size_t>(mappableFile.offset);
Michael Butlerab2f4822021-02-08 00:05:07 -0800373
Michael Butlerf03ebd92021-03-25 15:27:38 -0700374 return createSharedMemoryFromFd(size, prot, fd, offset);
375 }
376 case Tag::hardwareBuffer: {
Ray Hernandez338d6f82021-08-11 21:29:20 +0000377#ifdef __ANDROID__
Michael Butlerf03ebd92021-03-25 15:27:38 -0700378 const auto& hardwareBuffer = memory.get<Tag::hardwareBuffer>();
Michael Butlerab2f4822021-02-08 00:05:07 -0800379
Michael Butlerf03ebd92021-03-25 15:27:38 -0700380 const UniqueNativeHandle handle =
381 NN_TRY(nativeHandleFromAidlHandle(hardwareBuffer.handle));
382 const native_handle_t* nativeHandle = handle.get();
383
384 const AHardwareBuffer_Desc desc{
385 .width = static_cast<uint32_t>(hardwareBuffer.description.width),
386 .height = static_cast<uint32_t>(hardwareBuffer.description.height),
387 .layers = static_cast<uint32_t>(hardwareBuffer.description.layers),
388 .format = static_cast<uint32_t>(hardwareBuffer.description.format),
389 .usage = static_cast<uint64_t>(hardwareBuffer.description.usage),
390 .stride = static_cast<uint32_t>(hardwareBuffer.description.stride),
391 };
392 AHardwareBuffer* ahwb = nullptr;
393 const status_t status = AHardwareBuffer_createFromHandle(
394 &desc, nativeHandle, AHARDWAREBUFFER_CREATE_FROM_HANDLE_METHOD_CLONE, &ahwb);
395 if (status != NO_ERROR) {
396 return NN_ERROR() << "createFromHandle failed";
397 }
398
399 return createSharedMemoryFromAHWB(ahwb, /*takeOwnership=*/true);
Ray Hernandez338d6f82021-08-11 21:29:20 +0000400#else // __ANDROID__
401 LOG(FATAL) << "GeneralResult<SharedMemory> unvalidatedConvert(const aidl_hal::Memory& "
402 "memory): Not Available on Host Build";
403 return NN_ERROR() << "createFromHandle failed";
404#endif // __ANDROID__
Michael Butlerab2f4822021-02-08 00:05:07 -0800405 }
406 }
Michael Butlerf03ebd92021-03-25 15:27:38 -0700407 return NN_ERROR() << "Unrecognized Memory::Tag: " << memory.getTag();
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000408}
409
Lev Proleev900c28a2021-01-26 19:40:20 +0000410GeneralResult<Timing> unvalidatedConvert(const aidl_hal::Timing& timing) {
Lev Proleev8df7d6e2021-04-14 20:54:27 +0100411 if (timing.timeInDriverNs < -1) {
412 return NN_ERROR() << "Timing: timeInDriverNs must not be less than -1";
Lev Proleev900c28a2021-01-26 19:40:20 +0000413 }
Lev Proleev8df7d6e2021-04-14 20:54:27 +0100414 if (timing.timeOnDeviceNs < -1) {
415 return NN_ERROR() << "Timing: timeOnDeviceNs must not be less than -1";
Lev Proleev900c28a2021-01-26 19:40:20 +0000416 }
417 constexpr auto convertTiming = [](int64_t halTiming) -> OptionalDuration {
418 if (halTiming == kNoTiming) {
419 return {};
420 }
421 return nn::Duration(static_cast<uint64_t>(halTiming));
422 };
Lev Proleev8df7d6e2021-04-14 20:54:27 +0100423 return Timing{.timeOnDevice = convertTiming(timing.timeOnDeviceNs),
424 .timeInDriver = convertTiming(timing.timeInDriverNs)};
Lev Proleev900c28a2021-01-26 19:40:20 +0000425}
426
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000427GeneralResult<Model::OperandValues> unvalidatedConvert(const std::vector<uint8_t>& operandValues) {
428 return Model::OperandValues(operandValues.data(), operandValues.size());
429}
430
431GeneralResult<BufferDesc> unvalidatedConvert(const aidl_hal::BufferDesc& bufferDesc) {
432 return BufferDesc{.dimensions = NN_TRY(toUnsigned(bufferDesc.dimensions))};
433}
434
435GeneralResult<BufferRole> unvalidatedConvert(const aidl_hal::BufferRole& bufferRole) {
436 VERIFY_NON_NEGATIVE(bufferRole.modelIndex) << "BufferRole: modelIndex must not be negative";
437 VERIFY_NON_NEGATIVE(bufferRole.ioIndex) << "BufferRole: ioIndex must not be negative";
438 return BufferRole{
439 .modelIndex = static_cast<uint32_t>(bufferRole.modelIndex),
440 .ioIndex = static_cast<uint32_t>(bufferRole.ioIndex),
Xusong Wang3633d072021-03-19 13:58:24 -0700441 .probability = bufferRole.probability,
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000442 };
443}
444
445GeneralResult<Request> unvalidatedConvert(const aidl_hal::Request& request) {
446 return Request{
447 .inputs = NN_TRY(unvalidatedConvert(request.inputs)),
448 .outputs = NN_TRY(unvalidatedConvert(request.outputs)),
449 .pools = NN_TRY(unvalidatedConvert(request.pools)),
450 };
451}
452
453GeneralResult<Request::Argument> unvalidatedConvert(const aidl_hal::RequestArgument& argument) {
454 const auto lifetime = argument.hasNoValue ? Request::Argument::LifeTime::NO_VALUE
455 : Request::Argument::LifeTime::POOL;
456 return Request::Argument{
457 .lifetime = lifetime,
458 .location = NN_TRY(unvalidatedConvert(argument.location)),
459 .dimensions = NN_TRY(toUnsigned(argument.dimensions)),
460 };
461}
462
463GeneralResult<Request::MemoryPool> unvalidatedConvert(
464 const aidl_hal::RequestMemoryPool& memoryPool) {
465 using Tag = aidl_hal::RequestMemoryPool::Tag;
466 switch (memoryPool.getTag()) {
467 case Tag::pool:
468 return unvalidatedConvert(memoryPool.get<Tag::pool>());
469 case Tag::token: {
470 const auto token = memoryPool.get<Tag::token>();
471 VERIFY_NON_NEGATIVE(token) << "Memory pool token must not be negative";
472 return static_cast<Request::MemoryDomainToken>(token);
473 }
474 }
475 return NN_ERROR() << "Invalid Request::MemoryPool tag " << underlyingType(memoryPool.getTag());
476}
477
478GeneralResult<ErrorStatus> unvalidatedConvert(const aidl_hal::ErrorStatus& status) {
479 switch (status) {
480 case aidl_hal::ErrorStatus::NONE:
481 case aidl_hal::ErrorStatus::DEVICE_UNAVAILABLE:
482 case aidl_hal::ErrorStatus::GENERAL_FAILURE:
483 case aidl_hal::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
484 case aidl_hal::ErrorStatus::INVALID_ARGUMENT:
485 case aidl_hal::ErrorStatus::MISSED_DEADLINE_TRANSIENT:
486 case aidl_hal::ErrorStatus::MISSED_DEADLINE_PERSISTENT:
487 case aidl_hal::ErrorStatus::RESOURCE_EXHAUSTED_TRANSIENT:
488 case aidl_hal::ErrorStatus::RESOURCE_EXHAUSTED_PERSISTENT:
489 return static_cast<ErrorStatus>(status);
490 }
491 return NN_ERROR() << "Invalid ErrorStatus " << underlyingType(status);
492}
493
494GeneralResult<ExecutionPreference> unvalidatedConvert(
495 const aidl_hal::ExecutionPreference& executionPreference) {
496 return static_cast<ExecutionPreference>(executionPreference);
497}
498
Michael Butler388bceb2021-02-03 15:15:43 -0800499GeneralResult<std::vector<Operation>> unvalidatedConvert(
500 const std::vector<aidl_hal::Operation>& operations) {
501 return unvalidatedConvertVec(operations);
502}
503
Michael Butlere52a77e2021-06-07 13:10:58 -0700504GeneralResult<SharedHandle> unvalidatedConvert(const ndk::ScopedFileDescriptor& handle) {
505 auto duplicatedFd = NN_TRY(dupFd(handle.get()));
506 return std::make_shared<const Handle>(std::move(duplicatedFd));
Lev Proleev900c28a2021-01-26 19:40:20 +0000507}
508
509GeneralResult<Capabilities> convert(const aidl_hal::Capabilities& capabilities) {
510 return validatedConvert(capabilities);
511}
512
513GeneralResult<DeviceType> convert(const aidl_hal::DeviceType& deviceType) {
514 return validatedConvert(deviceType);
515}
516
517GeneralResult<ErrorStatus> convert(const aidl_hal::ErrorStatus& errorStatus) {
518 return validatedConvert(errorStatus);
519}
520
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000521GeneralResult<ExecutionPreference> convert(
522 const aidl_hal::ExecutionPreference& executionPreference) {
523 return validatedConvert(executionPreference);
524}
525
Michael Butlerfadeb8a2021-02-07 00:11:13 -0800526GeneralResult<SharedMemory> convert(const aidl_hal::Memory& operand) {
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000527 return validatedConvert(operand);
528}
529
530GeneralResult<Model> convert(const aidl_hal::Model& model) {
531 return validatedConvert(model);
532}
533
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000534GeneralResult<OperandType> convert(const aidl_hal::OperandType& operandType) {
Michael Butler388bceb2021-02-03 15:15:43 -0800535 return validatedConvert(operandType);
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000536}
537
538GeneralResult<Priority> convert(const aidl_hal::Priority& priority) {
539 return validatedConvert(priority);
540}
541
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000542GeneralResult<Request> convert(const aidl_hal::Request& request) {
543 return validatedConvert(request);
544}
545
Lev Proleev900c28a2021-01-26 19:40:20 +0000546GeneralResult<Timing> convert(const aidl_hal::Timing& timing) {
547 return validatedConvert(timing);
548}
549
Michael Butlere52a77e2021-06-07 13:10:58 -0700550GeneralResult<SharedHandle> convert(const ndk::ScopedFileDescriptor& handle) {
551 return validatedConvert(handle);
Lev Proleev900c28a2021-01-26 19:40:20 +0000552}
553
Michael Butler53455632021-10-25 11:20:33 -0700554GeneralResult<BufferDesc> convert(const aidl_hal::BufferDesc& bufferDesc) {
555 return validatedConvert(bufferDesc);
556}
557
Lev Proleev900c28a2021-01-26 19:40:20 +0000558GeneralResult<std::vector<Extension>> convert(const std::vector<aidl_hal::Extension>& extension) {
559 return validatedConvert(extension);
560}
561
Michael Butlerfadeb8a2021-02-07 00:11:13 -0800562GeneralResult<std::vector<SharedMemory>> convert(const std::vector<aidl_hal::Memory>& memories) {
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000563 return validatedConvert(memories);
564}
565
Lev Proleev900c28a2021-01-26 19:40:20 +0000566GeneralResult<std::vector<OutputShape>> convert(
567 const std::vector<aidl_hal::OutputShape>& outputShapes) {
568 return validatedConvert(outputShapes);
569}
570
Michael Butler53455632021-10-25 11:20:33 -0700571GeneralResult<std::vector<SharedHandle>> convert(
572 const std::vector<ndk::ScopedFileDescriptor>& handles) {
573 return validatedConvert(handles);
574}
575
576GeneralResult<std::vector<BufferRole>> convert(const std::vector<aidl_hal::BufferRole>& roles) {
577 return validatedConvert(roles);
578}
579
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000580GeneralResult<std::vector<uint32_t>> toUnsigned(const std::vector<int32_t>& vec) {
581 if (!std::all_of(vec.begin(), vec.end(), [](int32_t v) { return v >= 0; })) {
582 return NN_ERROR() << "Negative value passed to conversion from signed to unsigned";
583 }
584 return std::vector<uint32_t>(vec.begin(), vec.end());
585}
586
587} // namespace android::nn
588
589namespace aidl::android::hardware::neuralnetworks::utils {
590namespace {
591
Michael Butler53455632021-10-25 11:20:33 -0700592using utils::unvalidatedConvert;
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000593
Lev Proleev900c28a2021-01-26 19:40:20 +0000594// Helper template for std::visit
595template <class... Ts>
596struct overloaded : Ts... {
597 using Ts::operator()...;
598};
599template <class... Ts>
600overloaded(Ts...)->overloaded<Ts...>;
601
Ray Hernandez338d6f82021-08-11 21:29:20 +0000602#ifdef __ANDROID__
Michael Butlerf03ebd92021-03-25 15:27:38 -0700603nn::GeneralResult<common::NativeHandle> aidlHandleFromNativeHandle(
604 const native_handle_t& nativeHandle) {
605 auto handle = ::android::dupToAidl(&nativeHandle);
606 if (!std::all_of(handle.fds.begin(), handle.fds.end(),
607 [](const ndk::ScopedFileDescriptor& fd) { return fd.get() >= 0; })) {
608 return NN_ERROR() << "android::dupToAidl returned an invalid common::NativeHandle";
609 }
610 return handle;
611}
Ray Hernandez338d6f82021-08-11 21:29:20 +0000612#endif // __ANDROID__
Michael Butlerab2f4822021-02-08 00:05:07 -0800613
Michael Butlerf03ebd92021-03-25 15:27:38 -0700614nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::Ashmem& memory) {
615 if constexpr (std::numeric_limits<size_t>::max() > std::numeric_limits<int64_t>::max()) {
616 if (memory.size > std::numeric_limits<int64_t>::max()) {
617 return (
618 NN_ERROR()
619 << "Memory::Ashmem: size must be <= std::numeric_limits<int64_t>::max()")
620 .
621 operator nn::GeneralResult<Memory>();
622 }
Michael Butlerab2f4822021-02-08 00:05:07 -0800623 }
624
Michael Butlerf03ebd92021-03-25 15:27:38 -0700625 auto fd = NN_TRY(nn::dupFd(memory.fd));
626 auto handle = common::Ashmem{
627 .fd = ndk::ScopedFileDescriptor(fd.release()),
628 .size = static_cast<int64_t>(memory.size),
629 };
630 return Memory::make<Memory::Tag::ashmem>(std::move(handle));
631}
Michael Butlerab2f4822021-02-08 00:05:07 -0800632
Michael Butlerf03ebd92021-03-25 15:27:38 -0700633nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::Fd& memory) {
634 if constexpr (std::numeric_limits<size_t>::max() > std::numeric_limits<int64_t>::max()) {
635 if (memory.size > std::numeric_limits<int64_t>::max()) {
636 return (NN_ERROR() << "Memory::Fd: size must be <= std::numeric_limits<int64_t>::max()")
637 .
638 operator nn::GeneralResult<Memory>();
639 }
640 if (memory.offset > std::numeric_limits<int64_t>::max()) {
641 return (
642 NN_ERROR()
643 << "Memory::Fd: offset must be <= std::numeric_limits<int64_t>::max()")
644 .
645 operator nn::GeneralResult<Memory>();
646 }
647 }
648
649 auto fd = NN_TRY(nn::dupFd(memory.fd));
650 auto handle = common::MappableFile{
651 .length = static_cast<int64_t>(memory.size),
652 .prot = memory.prot,
653 .fd = ndk::ScopedFileDescriptor(fd.release()),
654 .offset = static_cast<int64_t>(memory.offset),
655 };
656 return Memory::make<Memory::Tag::mappableFile>(std::move(handle));
657}
658
659nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::HardwareBuffer& memory) {
Ray Hernandez338d6f82021-08-11 21:29:20 +0000660#ifdef __ANDROID__
Michael Butlerf03ebd92021-03-25 15:27:38 -0700661 const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(memory.handle.get());
662 if (nativeHandle == nullptr) {
663 return (NN_ERROR() << "unvalidatedConvert failed because AHardwareBuffer_getNativeHandle "
664 "returned nullptr")
665 .
666 operator nn::GeneralResult<Memory>();
667 }
668
669 auto handle = NN_TRY(aidlHandleFromNativeHandle(*nativeHandle));
670
671 AHardwareBuffer_Desc desc;
672 AHardwareBuffer_describe(memory.handle.get(), &desc);
673
674 const auto description = graphics::common::HardwareBufferDescription{
675 .width = static_cast<int32_t>(desc.width),
676 .height = static_cast<int32_t>(desc.height),
677 .layers = static_cast<int32_t>(desc.layers),
678 .format = static_cast<graphics::common::PixelFormat>(desc.format),
679 .usage = static_cast<graphics::common::BufferUsage>(desc.usage),
680 .stride = static_cast<int32_t>(desc.stride),
681 };
682
683 auto hardwareBuffer = graphics::common::HardwareBuffer{
684 .description = std::move(description),
685 .handle = std::move(handle),
686 };
687 return Memory::make<Memory::Tag::hardwareBuffer>(std::move(hardwareBuffer));
Ray Hernandez338d6f82021-08-11 21:29:20 +0000688#else // __ANDROID__
689 LOG(FATAL) << "nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::HardwareBuffer& "
690 "memory): Not Available on Host Build";
691 (void)memory;
692 return (NN_ERROR() << "unvalidatedConvert failed").operator nn::GeneralResult<Memory>();
693#endif // __ANDROID__
Michael Butlerf03ebd92021-03-25 15:27:38 -0700694}
695
696nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::Unknown& /*memory*/) {
697 return (NN_ERROR() << "Unable to convert Unknown memory type")
698 .
699 operator nn::GeneralResult<Memory>();
Michael Butlerab2f4822021-02-08 00:05:07 -0800700}
701
Michael Butler53455632021-10-25 11:20:33 -0700702nn::GeneralResult<PerformanceInfo> unvalidatedConvert(
703 const nn::Capabilities::PerformanceInfo& info) {
704 return PerformanceInfo{.execTime = info.execTime, .powerUsage = info.powerUsage};
705}
706
707nn::GeneralResult<OperandPerformance> unvalidatedConvert(
708 const nn::Capabilities::OperandPerformance& operandPerformance) {
709 return OperandPerformance{.type = NN_TRY(unvalidatedConvert(operandPerformance.type)),
710 .info = NN_TRY(unvalidatedConvert(operandPerformance.info))};
711}
712
713nn::GeneralResult<std::vector<OperandPerformance>> unvalidatedConvert(
714 const nn::Capabilities::OperandPerformanceTable& table) {
715 std::vector<OperandPerformance> operandPerformances;
716 operandPerformances.reserve(table.asVector().size());
717 for (const auto& operandPerformance : table.asVector()) {
718 operandPerformances.push_back(NN_TRY(unvalidatedConvert(operandPerformance)));
719 }
720 return operandPerformances;
721}
722
723nn::GeneralResult<ExtensionOperandTypeInformation> unvalidatedConvert(
724 const nn::Extension::OperandTypeInformation& info) {
725 return ExtensionOperandTypeInformation{.type = info.type,
726 .isTensor = info.isTensor,
727 .byteSize = static_cast<int32_t>(info.byteSize)};
728}
729
730nn::GeneralResult<int64_t> unvalidatedConvert(const nn::Duration& duration) {
731 if (duration < nn::Duration::zero()) {
732 return NN_ERROR() << "Unable to convert invalid (negative) duration";
733 }
734 constexpr std::chrono::nanoseconds::rep kIntMax = std::numeric_limits<int64_t>::max();
735 const auto count = duration.count();
736 return static_cast<int64_t>(std::min(count, kIntMax));
737}
738
739template <typename Input>
740using UnvalidatedConvertOutput =
741 std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
742
743template <typename Type>
744nn::GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
745 const std::vector<Type>& arguments) {
746 std::vector<UnvalidatedConvertOutput<Type>> halObject;
747 halObject.reserve(arguments.size());
748 for (const auto& argument : arguments) {
749 halObject.push_back(NN_TRY(unvalidatedConvert(argument)));
750 }
751 return halObject;
752}
753
754template <typename Type>
755nn::GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& canonical) {
756 NN_TRY(compliantVersion(canonical));
757 return utils::unvalidatedConvert(canonical);
758}
759
760template <typename Type>
761nn::GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> validatedConvert(
762 const std::vector<Type>& arguments) {
763 std::vector<UnvalidatedConvertOutput<Type>> halObject(arguments.size());
764 for (size_t i = 0; i < arguments.size(); ++i) {
765 halObject[i] = NN_TRY(validatedConvert(arguments[i]));
766 }
767 return halObject;
768}
769
Michael Butlerab2f4822021-02-08 00:05:07 -0800770} // namespace
771
Lev Proleev900c28a2021-01-26 19:40:20 +0000772nn::GeneralResult<std::vector<uint8_t>> unvalidatedConvert(const nn::CacheToken& cacheToken) {
773 return std::vector<uint8_t>(cacheToken.begin(), cacheToken.end());
774}
775
776nn::GeneralResult<BufferDesc> unvalidatedConvert(const nn::BufferDesc& bufferDesc) {
777 return BufferDesc{.dimensions = NN_TRY(toSigned(bufferDesc.dimensions))};
778}
779
780nn::GeneralResult<BufferRole> unvalidatedConvert(const nn::BufferRole& bufferRole) {
781 VERIFY_LE_INT32_MAX(bufferRole.modelIndex)
782 << "BufferRole: modelIndex must be <= std::numeric_limits<int32_t>::max()";
783 VERIFY_LE_INT32_MAX(bufferRole.ioIndex)
784 << "BufferRole: ioIndex must be <= std::numeric_limits<int32_t>::max()";
785 return BufferRole{
786 .modelIndex = static_cast<int32_t>(bufferRole.modelIndex),
787 .ioIndex = static_cast<int32_t>(bufferRole.ioIndex),
Xusong Wang3633d072021-03-19 13:58:24 -0700788 .probability = bufferRole.probability,
Lev Proleev900c28a2021-01-26 19:40:20 +0000789 };
790}
791
Michael Butler53455632021-10-25 11:20:33 -0700792nn::GeneralResult<DeviceType> unvalidatedConvert(const nn::DeviceType& deviceType) {
793 switch (deviceType) {
794 case nn::DeviceType::UNKNOWN:
795 break;
796 case nn::DeviceType::OTHER:
797 case nn::DeviceType::CPU:
798 case nn::DeviceType::GPU:
799 case nn::DeviceType::ACCELERATOR:
800 return static_cast<DeviceType>(deviceType);
801 }
802 return NN_ERROR() << "Invalid DeviceType " << deviceType;
803}
804
Lev Proleev900c28a2021-01-26 19:40:20 +0000805nn::GeneralResult<bool> unvalidatedConvert(const nn::MeasureTiming& measureTiming) {
806 return measureTiming == nn::MeasureTiming::YES;
807}
808
Michael Butlerfadeb8a2021-02-07 00:11:13 -0800809nn::GeneralResult<Memory> unvalidatedConvert(const nn::SharedMemory& memory) {
Michael Butlerf03ebd92021-03-25 15:27:38 -0700810 if (memory == nullptr) {
811 return (NN_ERROR() << "Unable to convert nullptr memory")
812 .
813 operator nn::GeneralResult<Memory>();
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000814 }
Michael Butlerf03ebd92021-03-25 15:27:38 -0700815 return std::visit([](const auto& x) { return unvalidatedConvert(x); }, memory->handle);
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000816}
817
818nn::GeneralResult<ErrorStatus> unvalidatedConvert(const nn::ErrorStatus& errorStatus) {
819 switch (errorStatus) {
820 case nn::ErrorStatus::NONE:
821 case nn::ErrorStatus::DEVICE_UNAVAILABLE:
822 case nn::ErrorStatus::GENERAL_FAILURE:
823 case nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
824 case nn::ErrorStatus::INVALID_ARGUMENT:
825 case nn::ErrorStatus::MISSED_DEADLINE_TRANSIENT:
826 case nn::ErrorStatus::MISSED_DEADLINE_PERSISTENT:
827 case nn::ErrorStatus::RESOURCE_EXHAUSTED_TRANSIENT:
828 case nn::ErrorStatus::RESOURCE_EXHAUSTED_PERSISTENT:
829 return static_cast<ErrorStatus>(errorStatus);
830 default:
831 return ErrorStatus::GENERAL_FAILURE;
832 }
833}
834
835nn::GeneralResult<OutputShape> unvalidatedConvert(const nn::OutputShape& outputShape) {
836 return OutputShape{.dimensions = NN_TRY(toSigned(outputShape.dimensions)),
837 .isSufficient = outputShape.isSufficient};
838}
839
Lev Proleev900c28a2021-01-26 19:40:20 +0000840nn::GeneralResult<ExecutionPreference> unvalidatedConvert(
841 const nn::ExecutionPreference& executionPreference) {
842 return static_cast<ExecutionPreference>(executionPreference);
843}
844
845nn::GeneralResult<OperandType> unvalidatedConvert(const nn::OperandType& operandType) {
Michael Butler388bceb2021-02-03 15:15:43 -0800846 if (operandType == nn::OperandType::OEM || operandType == nn::OperandType::TENSOR_OEM_BYTE) {
847 return NN_ERROR() << "Unable to convert invalid OperandType " << operandType;
848 }
Lev Proleev900c28a2021-01-26 19:40:20 +0000849 return static_cast<OperandType>(operandType);
850}
851
852nn::GeneralResult<OperandLifeTime> unvalidatedConvert(
853 const nn::Operand::LifeTime& operandLifeTime) {
854 return static_cast<OperandLifeTime>(operandLifeTime);
855}
856
857nn::GeneralResult<DataLocation> unvalidatedConvert(const nn::DataLocation& location) {
858 VERIFY_LE_INT32_MAX(location.poolIndex)
859 << "DataLocation: pool index must be <= std::numeric_limits<int32_t>::max()";
860 return DataLocation{
861 .poolIndex = static_cast<int32_t>(location.poolIndex),
862 .offset = static_cast<int64_t>(location.offset),
863 .length = static_cast<int64_t>(location.length),
864 };
865}
866
867nn::GeneralResult<std::optional<OperandExtraParams>> unvalidatedConvert(
868 const nn::Operand::ExtraParams& extraParams) {
869 return std::visit(
870 overloaded{
871 [](const nn::Operand::NoParams&)
872 -> nn::GeneralResult<std::optional<OperandExtraParams>> {
873 return std::nullopt;
874 },
875 [](const nn::Operand::SymmPerChannelQuantParams& symmPerChannelQuantParams)
876 -> nn::GeneralResult<std::optional<OperandExtraParams>> {
877 if (symmPerChannelQuantParams.channelDim >
878 std::numeric_limits<int32_t>::max()) {
879 // Using explicit type conversion because std::optional in successful
880 // result confuses the compiler.
881 return (NN_ERROR() << "symmPerChannelQuantParams.channelDim must be <= "
882 "std::numeric_limits<int32_t>::max(), received: "
883 << symmPerChannelQuantParams.channelDim)
884 .
885 operator nn::GeneralResult<std::optional<OperandExtraParams>>();
886 }
887 return OperandExtraParams::make<OperandExtraParams::Tag::channelQuant>(
888 SymmPerChannelQuantParams{
889 .scales = symmPerChannelQuantParams.scales,
890 .channelDim = static_cast<int32_t>(
891 symmPerChannelQuantParams.channelDim),
892 });
893 },
894 [](const nn::Operand::ExtensionParams& extensionParams)
895 -> nn::GeneralResult<std::optional<OperandExtraParams>> {
896 return OperandExtraParams::make<OperandExtraParams::Tag::extension>(
897 extensionParams);
898 },
899 },
900 extraParams);
901}
902
903nn::GeneralResult<Operand> unvalidatedConvert(const nn::Operand& operand) {
904 return Operand{
905 .type = NN_TRY(unvalidatedConvert(operand.type)),
906 .dimensions = NN_TRY(toSigned(operand.dimensions)),
907 .scale = operand.scale,
908 .zeroPoint = operand.zeroPoint,
909 .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
910 .location = NN_TRY(unvalidatedConvert(operand.location)),
911 .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
912 };
913}
914
915nn::GeneralResult<OperationType> unvalidatedConvert(const nn::OperationType& operationType) {
Michael Butler388bceb2021-02-03 15:15:43 -0800916 if (operationType == nn::OperationType::OEM_OPERATION) {
917 return NN_ERROR() << "Unable to convert invalid OperationType OEM_OPERATION";
918 }
Lev Proleev900c28a2021-01-26 19:40:20 +0000919 return static_cast<OperationType>(operationType);
920}
921
922nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation) {
923 return Operation{
924 .type = NN_TRY(unvalidatedConvert(operation.type)),
925 .inputs = NN_TRY(toSigned(operation.inputs)),
926 .outputs = NN_TRY(toSigned(operation.outputs)),
927 };
928}
929
930nn::GeneralResult<Subgraph> unvalidatedConvert(const nn::Model::Subgraph& subgraph) {
931 return Subgraph{
932 .operands = NN_TRY(unvalidatedConvert(subgraph.operands)),
933 .operations = NN_TRY(unvalidatedConvert(subgraph.operations)),
934 .inputIndexes = NN_TRY(toSigned(subgraph.inputIndexes)),
935 .outputIndexes = NN_TRY(toSigned(subgraph.outputIndexes)),
936 };
937}
938
939nn::GeneralResult<std::vector<uint8_t>> unvalidatedConvert(
940 const nn::Model::OperandValues& operandValues) {
941 return std::vector<uint8_t>(operandValues.data(), operandValues.data() + operandValues.size());
942}
943
944nn::GeneralResult<ExtensionNameAndPrefix> unvalidatedConvert(
945 const nn::Model::ExtensionNameAndPrefix& extensionNameToPrefix) {
946 return ExtensionNameAndPrefix{
947 .name = extensionNameToPrefix.name,
948 .prefix = extensionNameToPrefix.prefix,
949 };
950}
951
952nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model) {
953 return Model{
954 .main = NN_TRY(unvalidatedConvert(model.main)),
955 .referenced = NN_TRY(unvalidatedConvert(model.referenced)),
956 .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
957 .pools = NN_TRY(unvalidatedConvert(model.pools)),
958 .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
959 .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
960 };
961}
962
963nn::GeneralResult<Priority> unvalidatedConvert(const nn::Priority& priority) {
964 return static_cast<Priority>(priority);
965}
966
967nn::GeneralResult<Request> unvalidatedConvert(const nn::Request& request) {
968 return Request{
969 .inputs = NN_TRY(unvalidatedConvert(request.inputs)),
970 .outputs = NN_TRY(unvalidatedConvert(request.outputs)),
971 .pools = NN_TRY(unvalidatedConvert(request.pools)),
972 };
973}
974
975nn::GeneralResult<RequestArgument> unvalidatedConvert(
976 const nn::Request::Argument& requestArgument) {
977 if (requestArgument.lifetime == nn::Request::Argument::LifeTime::POINTER) {
978 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
979 << "Request cannot be unvalidatedConverted because it contains pointer-based memory";
980 }
981 const bool hasNoValue = requestArgument.lifetime == nn::Request::Argument::LifeTime::NO_VALUE;
982 return RequestArgument{
983 .hasNoValue = hasNoValue,
984 .location = NN_TRY(unvalidatedConvert(requestArgument.location)),
985 .dimensions = NN_TRY(toSigned(requestArgument.dimensions)),
986 };
987}
988
989nn::GeneralResult<RequestMemoryPool> unvalidatedConvert(const nn::Request::MemoryPool& memoryPool) {
990 return std::visit(
991 overloaded{
992 [](const nn::SharedMemory& memory) -> nn::GeneralResult<RequestMemoryPool> {
993 return RequestMemoryPool::make<RequestMemoryPool::Tag::pool>(
994 NN_TRY(unvalidatedConvert(memory)));
995 },
996 [](const nn::Request::MemoryDomainToken& token)
997 -> nn::GeneralResult<RequestMemoryPool> {
998 return RequestMemoryPool::make<RequestMemoryPool::Tag::token>(
999 underlyingType(token));
1000 },
1001 [](const nn::SharedBuffer& /*buffer*/) {
1002 return (NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
1003 << "Unable to make memory pool from IBuffer")
1004 .
1005 operator nn::GeneralResult<RequestMemoryPool>();
1006 },
1007 },
1008 memoryPool);
1009}
1010
1011nn::GeneralResult<Timing> unvalidatedConvert(const nn::Timing& timing) {
1012 return Timing{
Lev Proleev8df7d6e2021-04-14 20:54:27 +01001013 .timeOnDeviceNs = NN_TRY(unvalidatedConvert(timing.timeOnDevice)),
1014 .timeInDriverNs = NN_TRY(unvalidatedConvert(timing.timeInDriver)),
Lev Proleev900c28a2021-01-26 19:40:20 +00001015 };
1016}
1017
Lev Proleev900c28a2021-01-26 19:40:20 +00001018nn::GeneralResult<int64_t> unvalidatedConvert(const nn::OptionalDuration& optionalDuration) {
1019 if (!optionalDuration.has_value()) {
1020 return kNoTiming;
1021 }
1022 return unvalidatedConvert(optionalDuration.value());
1023}
1024
1025nn::GeneralResult<int64_t> unvalidatedConvert(const nn::OptionalTimePoint& optionalTimePoint) {
1026 if (!optionalTimePoint.has_value()) {
1027 return kNoTiming;
1028 }
1029 return unvalidatedConvert(optionalTimePoint->time_since_epoch());
1030}
1031
1032nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvert(const nn::SyncFence& syncFence) {
1033 auto duplicatedFd = NN_TRY(nn::dupFd(syncFence.getFd()));
1034 return ndk::ScopedFileDescriptor(duplicatedFd.release());
1035}
1036
Michael Butlere52a77e2021-06-07 13:10:58 -07001037nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvert(const nn::SharedHandle& handle) {
1038 auto duplicatedFd = NN_TRY(nn::dupFd(handle->get()));
Lev Proleev900c28a2021-01-26 19:40:20 +00001039 return ndk::ScopedFileDescriptor(duplicatedFd.release());
1040}
1041
Michael Butler53455632021-10-25 11:20:33 -07001042nn::GeneralResult<Capabilities> unvalidatedConvert(const nn::Capabilities& capabilities) {
1043 return Capabilities{
1044 .relaxedFloat32toFloat16PerformanceTensor = NN_TRY(
1045 unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceTensor)),
1046 .relaxedFloat32toFloat16PerformanceScalar = NN_TRY(
1047 unvalidatedConvert(capabilities.relaxedFloat32toFloat16PerformanceScalar)),
1048 .operandPerformance = NN_TRY(unvalidatedConvert(capabilities.operandPerformance)),
1049 .ifPerformance = NN_TRY(unvalidatedConvert(capabilities.ifPerformance)),
1050 .whilePerformance = NN_TRY(unvalidatedConvert(capabilities.whilePerformance)),
1051 };
1052}
1053
1054nn::GeneralResult<Extension> unvalidatedConvert(const nn::Extension& extension) {
1055 return Extension{.name = extension.name,
1056 .operandTypes = NN_TRY(unvalidatedConvert(extension.operandTypes))};
1057}
1058
Lev Proleev900c28a2021-01-26 19:40:20 +00001059nn::GeneralResult<std::vector<uint8_t>> convert(const nn::CacheToken& cacheToken) {
Michael Butler388bceb2021-02-03 15:15:43 -08001060 return validatedConvert(cacheToken);
Lev Proleev900c28a2021-01-26 19:40:20 +00001061}
1062
1063nn::GeneralResult<BufferDesc> convert(const nn::BufferDesc& bufferDesc) {
1064 return validatedConvert(bufferDesc);
1065}
1066
Michael Butler53455632021-10-25 11:20:33 -07001067nn::GeneralResult<DeviceType> convert(const nn::DeviceType& deviceType) {
1068 return validatedConvert(deviceType);
1069}
1070
Lev Proleev900c28a2021-01-26 19:40:20 +00001071nn::GeneralResult<bool> convert(const nn::MeasureTiming& measureTiming) {
1072 return validatedConvert(measureTiming);
1073}
1074
Michael Butlerfadeb8a2021-02-07 00:11:13 -08001075nn::GeneralResult<Memory> convert(const nn::SharedMemory& memory) {
Lev Proleev6b6dfcd2020-11-11 18:28:50 +00001076 return validatedConvert(memory);
1077}
1078
1079nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& errorStatus) {
1080 return validatedConvert(errorStatus);
1081}
1082
Lev Proleev900c28a2021-01-26 19:40:20 +00001083nn::GeneralResult<ExecutionPreference> convert(const nn::ExecutionPreference& executionPreference) {
1084 return validatedConvert(executionPreference);
1085}
1086
1087nn::GeneralResult<Model> convert(const nn::Model& model) {
1088 return validatedConvert(model);
1089}
1090
1091nn::GeneralResult<Priority> convert(const nn::Priority& priority) {
1092 return validatedConvert(priority);
1093}
1094
1095nn::GeneralResult<Request> convert(const nn::Request& request) {
1096 return validatedConvert(request);
1097}
1098
1099nn::GeneralResult<Timing> convert(const nn::Timing& timing) {
1100 return validatedConvert(timing);
1101}
1102
1103nn::GeneralResult<int64_t> convert(const nn::OptionalDuration& optionalDuration) {
1104 return validatedConvert(optionalDuration);
1105}
1106
1107nn::GeneralResult<int64_t> convert(const nn::OptionalTimePoint& outputShapes) {
1108 return validatedConvert(outputShapes);
1109}
1110
Michael Butler53455632021-10-25 11:20:33 -07001111nn::GeneralResult<Capabilities> convert(const nn::Capabilities& capabilities) {
1112 return validatedConvert(capabilities);
1113}
1114
1115nn::GeneralResult<Extension> convert(const nn::Extension& extension) {
1116 return validatedConvert(extension);
1117}
1118
Lev Proleev900c28a2021-01-26 19:40:20 +00001119nn::GeneralResult<std::vector<BufferRole>> convert(const std::vector<nn::BufferRole>& bufferRoles) {
1120 return validatedConvert(bufferRoles);
1121}
1122
Lev Proleev6b6dfcd2020-11-11 18:28:50 +00001123nn::GeneralResult<std::vector<OutputShape>> convert(
1124 const std::vector<nn::OutputShape>& outputShapes) {
1125 return validatedConvert(outputShapes);
1126}
1127
Lev Proleev900c28a2021-01-26 19:40:20 +00001128nn::GeneralResult<std::vector<ndk::ScopedFileDescriptor>> convert(
1129 const std::vector<nn::SharedHandle>& cacheHandles) {
Michael Butlere52a77e2021-06-07 13:10:58 -07001130 return validatedConvert(cacheHandles);
Lev Proleev900c28a2021-01-26 19:40:20 +00001131}
1132
1133nn::GeneralResult<std::vector<ndk::ScopedFileDescriptor>> convert(
1134 const std::vector<nn::SyncFence>& syncFences) {
Michael Butler388bceb2021-02-03 15:15:43 -08001135 return validatedConvert(syncFences);
Lev Proleev900c28a2021-01-26 19:40:20 +00001136}
1137
Michael Butler53455632021-10-25 11:20:33 -07001138nn::GeneralResult<std::vector<Extension>> convert(const std::vector<nn::Extension>& extensions) {
1139 return validatedConvert(extensions);
1140}
1141
Lev Proleev6b6dfcd2020-11-11 18:28:50 +00001142nn::GeneralResult<std::vector<int32_t>> toSigned(const std::vector<uint32_t>& vec) {
1143 if (!std::all_of(vec.begin(), vec.end(),
1144 [](uint32_t v) { return v <= std::numeric_limits<int32_t>::max(); })) {
1145 return NN_ERROR() << "Vector contains a value that doesn't fit into int32_t.";
1146 }
1147 return std::vector<int32_t>(vec.begin(), vec.end());
1148}
1149
1150} // namespace aidl::android::hardware::neuralnetworks::utils