blob: 45628c8e7322c2fa7fa63dce7a001519ce16d941 [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
554GeneralResult<std::vector<Extension>> convert(const std::vector<aidl_hal::Extension>& extension) {
555 return validatedConvert(extension);
556}
557
Michael Butlerfadeb8a2021-02-07 00:11:13 -0800558GeneralResult<std::vector<SharedMemory>> convert(const std::vector<aidl_hal::Memory>& memories) {
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000559 return validatedConvert(memories);
560}
561
Lev Proleev900c28a2021-01-26 19:40:20 +0000562GeneralResult<std::vector<OutputShape>> convert(
563 const std::vector<aidl_hal::OutputShape>& outputShapes) {
564 return validatedConvert(outputShapes);
565}
566
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000567GeneralResult<std::vector<uint32_t>> toUnsigned(const std::vector<int32_t>& vec) {
568 if (!std::all_of(vec.begin(), vec.end(), [](int32_t v) { return v >= 0; })) {
569 return NN_ERROR() << "Negative value passed to conversion from signed to unsigned";
570 }
571 return std::vector<uint32_t>(vec.begin(), vec.end());
572}
573
574} // namespace android::nn
575
576namespace aidl::android::hardware::neuralnetworks::utils {
577namespace {
578
579template <typename Input>
580using UnvalidatedConvertOutput =
581 std::decay_t<decltype(unvalidatedConvert(std::declval<Input>()).value())>;
582
583template <typename Type>
584nn::GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvertVec(
585 const std::vector<Type>& arguments) {
Lev Proleev900c28a2021-01-26 19:40:20 +0000586 std::vector<UnvalidatedConvertOutput<Type>> halObject;
587 halObject.reserve(arguments.size());
588 for (const auto& argument : arguments) {
589 halObject.push_back(NN_TRY(unvalidatedConvert(argument)));
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000590 }
591 return halObject;
592}
593
594template <typename Type>
Lev Proleev900c28a2021-01-26 19:40:20 +0000595nn::GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> unvalidatedConvert(
596 const std::vector<Type>& arguments) {
597 return unvalidatedConvertVec(arguments);
598}
599
600template <typename Type>
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000601nn::GeneralResult<UnvalidatedConvertOutput<Type>> validatedConvert(const Type& canonical) {
Michael Butler388bceb2021-02-03 15:15:43 -0800602 NN_TRY(compliantVersion(canonical));
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000603 return utils::unvalidatedConvert(canonical);
604}
605
606template <typename Type>
607nn::GeneralResult<std::vector<UnvalidatedConvertOutput<Type>>> validatedConvert(
608 const std::vector<Type>& arguments) {
609 std::vector<UnvalidatedConvertOutput<Type>> halObject(arguments.size());
610 for (size_t i = 0; i < arguments.size(); ++i) {
611 halObject[i] = NN_TRY(validatedConvert(arguments[i]));
612 }
613 return halObject;
614}
615
Lev Proleev900c28a2021-01-26 19:40:20 +0000616// Helper template for std::visit
617template <class... Ts>
618struct overloaded : Ts... {
619 using Ts::operator()...;
620};
621template <class... Ts>
622overloaded(Ts...)->overloaded<Ts...>;
623
Ray Hernandez338d6f82021-08-11 21:29:20 +0000624#ifdef __ANDROID__
Michael Butlerf03ebd92021-03-25 15:27:38 -0700625nn::GeneralResult<common::NativeHandle> aidlHandleFromNativeHandle(
626 const native_handle_t& nativeHandle) {
627 auto handle = ::android::dupToAidl(&nativeHandle);
628 if (!std::all_of(handle.fds.begin(), handle.fds.end(),
629 [](const ndk::ScopedFileDescriptor& fd) { return fd.get() >= 0; })) {
630 return NN_ERROR() << "android::dupToAidl returned an invalid common::NativeHandle";
631 }
632 return handle;
633}
Ray Hernandez338d6f82021-08-11 21:29:20 +0000634#endif // __ANDROID__
Michael Butlerab2f4822021-02-08 00:05:07 -0800635
Michael Butlerf03ebd92021-03-25 15:27:38 -0700636nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::Ashmem& memory) {
637 if constexpr (std::numeric_limits<size_t>::max() > std::numeric_limits<int64_t>::max()) {
638 if (memory.size > std::numeric_limits<int64_t>::max()) {
639 return (
640 NN_ERROR()
641 << "Memory::Ashmem: size must be <= std::numeric_limits<int64_t>::max()")
642 .
643 operator nn::GeneralResult<Memory>();
644 }
Michael Butlerab2f4822021-02-08 00:05:07 -0800645 }
646
Michael Butlerf03ebd92021-03-25 15:27:38 -0700647 auto fd = NN_TRY(nn::dupFd(memory.fd));
648 auto handle = common::Ashmem{
649 .fd = ndk::ScopedFileDescriptor(fd.release()),
650 .size = static_cast<int64_t>(memory.size),
651 };
652 return Memory::make<Memory::Tag::ashmem>(std::move(handle));
653}
Michael Butlerab2f4822021-02-08 00:05:07 -0800654
Michael Butlerf03ebd92021-03-25 15:27:38 -0700655nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::Fd& memory) {
656 if constexpr (std::numeric_limits<size_t>::max() > std::numeric_limits<int64_t>::max()) {
657 if (memory.size > std::numeric_limits<int64_t>::max()) {
658 return (NN_ERROR() << "Memory::Fd: size must be <= std::numeric_limits<int64_t>::max()")
659 .
660 operator nn::GeneralResult<Memory>();
661 }
662 if (memory.offset > std::numeric_limits<int64_t>::max()) {
663 return (
664 NN_ERROR()
665 << "Memory::Fd: offset must be <= std::numeric_limits<int64_t>::max()")
666 .
667 operator nn::GeneralResult<Memory>();
668 }
669 }
670
671 auto fd = NN_TRY(nn::dupFd(memory.fd));
672 auto handle = common::MappableFile{
673 .length = static_cast<int64_t>(memory.size),
674 .prot = memory.prot,
675 .fd = ndk::ScopedFileDescriptor(fd.release()),
676 .offset = static_cast<int64_t>(memory.offset),
677 };
678 return Memory::make<Memory::Tag::mappableFile>(std::move(handle));
679}
680
681nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::HardwareBuffer& memory) {
Ray Hernandez338d6f82021-08-11 21:29:20 +0000682#ifdef __ANDROID__
Michael Butlerf03ebd92021-03-25 15:27:38 -0700683 const native_handle_t* nativeHandle = AHardwareBuffer_getNativeHandle(memory.handle.get());
684 if (nativeHandle == nullptr) {
685 return (NN_ERROR() << "unvalidatedConvert failed because AHardwareBuffer_getNativeHandle "
686 "returned nullptr")
687 .
688 operator nn::GeneralResult<Memory>();
689 }
690
691 auto handle = NN_TRY(aidlHandleFromNativeHandle(*nativeHandle));
692
693 AHardwareBuffer_Desc desc;
694 AHardwareBuffer_describe(memory.handle.get(), &desc);
695
696 const auto description = graphics::common::HardwareBufferDescription{
697 .width = static_cast<int32_t>(desc.width),
698 .height = static_cast<int32_t>(desc.height),
699 .layers = static_cast<int32_t>(desc.layers),
700 .format = static_cast<graphics::common::PixelFormat>(desc.format),
701 .usage = static_cast<graphics::common::BufferUsage>(desc.usage),
702 .stride = static_cast<int32_t>(desc.stride),
703 };
704
705 auto hardwareBuffer = graphics::common::HardwareBuffer{
706 .description = std::move(description),
707 .handle = std::move(handle),
708 };
709 return Memory::make<Memory::Tag::hardwareBuffer>(std::move(hardwareBuffer));
Ray Hernandez338d6f82021-08-11 21:29:20 +0000710#else // __ANDROID__
711 LOG(FATAL) << "nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::HardwareBuffer& "
712 "memory): Not Available on Host Build";
713 (void)memory;
714 return (NN_ERROR() << "unvalidatedConvert failed").operator nn::GeneralResult<Memory>();
715#endif // __ANDROID__
Michael Butlerf03ebd92021-03-25 15:27:38 -0700716}
717
718nn::GeneralResult<Memory> unvalidatedConvert(const nn::Memory::Unknown& /*memory*/) {
719 return (NN_ERROR() << "Unable to convert Unknown memory type")
720 .
721 operator nn::GeneralResult<Memory>();
Michael Butlerab2f4822021-02-08 00:05:07 -0800722}
723
724} // namespace
725
Lev Proleev900c28a2021-01-26 19:40:20 +0000726nn::GeneralResult<std::vector<uint8_t>> unvalidatedConvert(const nn::CacheToken& cacheToken) {
727 return std::vector<uint8_t>(cacheToken.begin(), cacheToken.end());
728}
729
730nn::GeneralResult<BufferDesc> unvalidatedConvert(const nn::BufferDesc& bufferDesc) {
731 return BufferDesc{.dimensions = NN_TRY(toSigned(bufferDesc.dimensions))};
732}
733
734nn::GeneralResult<BufferRole> unvalidatedConvert(const nn::BufferRole& bufferRole) {
735 VERIFY_LE_INT32_MAX(bufferRole.modelIndex)
736 << "BufferRole: modelIndex must be <= std::numeric_limits<int32_t>::max()";
737 VERIFY_LE_INT32_MAX(bufferRole.ioIndex)
738 << "BufferRole: ioIndex must be <= std::numeric_limits<int32_t>::max()";
739 return BufferRole{
740 .modelIndex = static_cast<int32_t>(bufferRole.modelIndex),
741 .ioIndex = static_cast<int32_t>(bufferRole.ioIndex),
Xusong Wang3633d072021-03-19 13:58:24 -0700742 .probability = bufferRole.probability,
Lev Proleev900c28a2021-01-26 19:40:20 +0000743 };
744}
745
746nn::GeneralResult<bool> unvalidatedConvert(const nn::MeasureTiming& measureTiming) {
747 return measureTiming == nn::MeasureTiming::YES;
748}
749
Michael Butlerfadeb8a2021-02-07 00:11:13 -0800750nn::GeneralResult<Memory> unvalidatedConvert(const nn::SharedMemory& memory) {
Michael Butlerf03ebd92021-03-25 15:27:38 -0700751 if (memory == nullptr) {
752 return (NN_ERROR() << "Unable to convert nullptr memory")
753 .
754 operator nn::GeneralResult<Memory>();
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000755 }
Michael Butlerf03ebd92021-03-25 15:27:38 -0700756 return std::visit([](const auto& x) { return unvalidatedConvert(x); }, memory->handle);
Lev Proleev6b6dfcd2020-11-11 18:28:50 +0000757}
758
759nn::GeneralResult<ErrorStatus> unvalidatedConvert(const nn::ErrorStatus& errorStatus) {
760 switch (errorStatus) {
761 case nn::ErrorStatus::NONE:
762 case nn::ErrorStatus::DEVICE_UNAVAILABLE:
763 case nn::ErrorStatus::GENERAL_FAILURE:
764 case nn::ErrorStatus::OUTPUT_INSUFFICIENT_SIZE:
765 case nn::ErrorStatus::INVALID_ARGUMENT:
766 case nn::ErrorStatus::MISSED_DEADLINE_TRANSIENT:
767 case nn::ErrorStatus::MISSED_DEADLINE_PERSISTENT:
768 case nn::ErrorStatus::RESOURCE_EXHAUSTED_TRANSIENT:
769 case nn::ErrorStatus::RESOURCE_EXHAUSTED_PERSISTENT:
770 return static_cast<ErrorStatus>(errorStatus);
771 default:
772 return ErrorStatus::GENERAL_FAILURE;
773 }
774}
775
776nn::GeneralResult<OutputShape> unvalidatedConvert(const nn::OutputShape& outputShape) {
777 return OutputShape{.dimensions = NN_TRY(toSigned(outputShape.dimensions)),
778 .isSufficient = outputShape.isSufficient};
779}
780
Lev Proleev900c28a2021-01-26 19:40:20 +0000781nn::GeneralResult<ExecutionPreference> unvalidatedConvert(
782 const nn::ExecutionPreference& executionPreference) {
783 return static_cast<ExecutionPreference>(executionPreference);
784}
785
786nn::GeneralResult<OperandType> unvalidatedConvert(const nn::OperandType& operandType) {
Michael Butler388bceb2021-02-03 15:15:43 -0800787 if (operandType == nn::OperandType::OEM || operandType == nn::OperandType::TENSOR_OEM_BYTE) {
788 return NN_ERROR() << "Unable to convert invalid OperandType " << operandType;
789 }
Lev Proleev900c28a2021-01-26 19:40:20 +0000790 return static_cast<OperandType>(operandType);
791}
792
793nn::GeneralResult<OperandLifeTime> unvalidatedConvert(
794 const nn::Operand::LifeTime& operandLifeTime) {
795 return static_cast<OperandLifeTime>(operandLifeTime);
796}
797
798nn::GeneralResult<DataLocation> unvalidatedConvert(const nn::DataLocation& location) {
799 VERIFY_LE_INT32_MAX(location.poolIndex)
800 << "DataLocation: pool index must be <= std::numeric_limits<int32_t>::max()";
801 return DataLocation{
802 .poolIndex = static_cast<int32_t>(location.poolIndex),
803 .offset = static_cast<int64_t>(location.offset),
804 .length = static_cast<int64_t>(location.length),
805 };
806}
807
808nn::GeneralResult<std::optional<OperandExtraParams>> unvalidatedConvert(
809 const nn::Operand::ExtraParams& extraParams) {
810 return std::visit(
811 overloaded{
812 [](const nn::Operand::NoParams&)
813 -> nn::GeneralResult<std::optional<OperandExtraParams>> {
814 return std::nullopt;
815 },
816 [](const nn::Operand::SymmPerChannelQuantParams& symmPerChannelQuantParams)
817 -> nn::GeneralResult<std::optional<OperandExtraParams>> {
818 if (symmPerChannelQuantParams.channelDim >
819 std::numeric_limits<int32_t>::max()) {
820 // Using explicit type conversion because std::optional in successful
821 // result confuses the compiler.
822 return (NN_ERROR() << "symmPerChannelQuantParams.channelDim must be <= "
823 "std::numeric_limits<int32_t>::max(), received: "
824 << symmPerChannelQuantParams.channelDim)
825 .
826 operator nn::GeneralResult<std::optional<OperandExtraParams>>();
827 }
828 return OperandExtraParams::make<OperandExtraParams::Tag::channelQuant>(
829 SymmPerChannelQuantParams{
830 .scales = symmPerChannelQuantParams.scales,
831 .channelDim = static_cast<int32_t>(
832 symmPerChannelQuantParams.channelDim),
833 });
834 },
835 [](const nn::Operand::ExtensionParams& extensionParams)
836 -> nn::GeneralResult<std::optional<OperandExtraParams>> {
837 return OperandExtraParams::make<OperandExtraParams::Tag::extension>(
838 extensionParams);
839 },
840 },
841 extraParams);
842}
843
844nn::GeneralResult<Operand> unvalidatedConvert(const nn::Operand& operand) {
845 return Operand{
846 .type = NN_TRY(unvalidatedConvert(operand.type)),
847 .dimensions = NN_TRY(toSigned(operand.dimensions)),
848 .scale = operand.scale,
849 .zeroPoint = operand.zeroPoint,
850 .lifetime = NN_TRY(unvalidatedConvert(operand.lifetime)),
851 .location = NN_TRY(unvalidatedConvert(operand.location)),
852 .extraParams = NN_TRY(unvalidatedConvert(operand.extraParams)),
853 };
854}
855
856nn::GeneralResult<OperationType> unvalidatedConvert(const nn::OperationType& operationType) {
Michael Butler388bceb2021-02-03 15:15:43 -0800857 if (operationType == nn::OperationType::OEM_OPERATION) {
858 return NN_ERROR() << "Unable to convert invalid OperationType OEM_OPERATION";
859 }
Lev Proleev900c28a2021-01-26 19:40:20 +0000860 return static_cast<OperationType>(operationType);
861}
862
863nn::GeneralResult<Operation> unvalidatedConvert(const nn::Operation& operation) {
864 return Operation{
865 .type = NN_TRY(unvalidatedConvert(operation.type)),
866 .inputs = NN_TRY(toSigned(operation.inputs)),
867 .outputs = NN_TRY(toSigned(operation.outputs)),
868 };
869}
870
871nn::GeneralResult<Subgraph> unvalidatedConvert(const nn::Model::Subgraph& subgraph) {
872 return Subgraph{
873 .operands = NN_TRY(unvalidatedConvert(subgraph.operands)),
874 .operations = NN_TRY(unvalidatedConvert(subgraph.operations)),
875 .inputIndexes = NN_TRY(toSigned(subgraph.inputIndexes)),
876 .outputIndexes = NN_TRY(toSigned(subgraph.outputIndexes)),
877 };
878}
879
880nn::GeneralResult<std::vector<uint8_t>> unvalidatedConvert(
881 const nn::Model::OperandValues& operandValues) {
882 return std::vector<uint8_t>(operandValues.data(), operandValues.data() + operandValues.size());
883}
884
885nn::GeneralResult<ExtensionNameAndPrefix> unvalidatedConvert(
886 const nn::Model::ExtensionNameAndPrefix& extensionNameToPrefix) {
887 return ExtensionNameAndPrefix{
888 .name = extensionNameToPrefix.name,
889 .prefix = extensionNameToPrefix.prefix,
890 };
891}
892
893nn::GeneralResult<Model> unvalidatedConvert(const nn::Model& model) {
894 return Model{
895 .main = NN_TRY(unvalidatedConvert(model.main)),
896 .referenced = NN_TRY(unvalidatedConvert(model.referenced)),
897 .operandValues = NN_TRY(unvalidatedConvert(model.operandValues)),
898 .pools = NN_TRY(unvalidatedConvert(model.pools)),
899 .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16,
900 .extensionNameToPrefix = NN_TRY(unvalidatedConvert(model.extensionNameToPrefix)),
901 };
902}
903
904nn::GeneralResult<Priority> unvalidatedConvert(const nn::Priority& priority) {
905 return static_cast<Priority>(priority);
906}
907
908nn::GeneralResult<Request> unvalidatedConvert(const nn::Request& request) {
909 return Request{
910 .inputs = NN_TRY(unvalidatedConvert(request.inputs)),
911 .outputs = NN_TRY(unvalidatedConvert(request.outputs)),
912 .pools = NN_TRY(unvalidatedConvert(request.pools)),
913 };
914}
915
916nn::GeneralResult<RequestArgument> unvalidatedConvert(
917 const nn::Request::Argument& requestArgument) {
918 if (requestArgument.lifetime == nn::Request::Argument::LifeTime::POINTER) {
919 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
920 << "Request cannot be unvalidatedConverted because it contains pointer-based memory";
921 }
922 const bool hasNoValue = requestArgument.lifetime == nn::Request::Argument::LifeTime::NO_VALUE;
923 return RequestArgument{
924 .hasNoValue = hasNoValue,
925 .location = NN_TRY(unvalidatedConvert(requestArgument.location)),
926 .dimensions = NN_TRY(toSigned(requestArgument.dimensions)),
927 };
928}
929
930nn::GeneralResult<RequestMemoryPool> unvalidatedConvert(const nn::Request::MemoryPool& memoryPool) {
931 return std::visit(
932 overloaded{
933 [](const nn::SharedMemory& memory) -> nn::GeneralResult<RequestMemoryPool> {
934 return RequestMemoryPool::make<RequestMemoryPool::Tag::pool>(
935 NN_TRY(unvalidatedConvert(memory)));
936 },
937 [](const nn::Request::MemoryDomainToken& token)
938 -> nn::GeneralResult<RequestMemoryPool> {
939 return RequestMemoryPool::make<RequestMemoryPool::Tag::token>(
940 underlyingType(token));
941 },
942 [](const nn::SharedBuffer& /*buffer*/) {
943 return (NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
944 << "Unable to make memory pool from IBuffer")
945 .
946 operator nn::GeneralResult<RequestMemoryPool>();
947 },
948 },
949 memoryPool);
950}
951
952nn::GeneralResult<Timing> unvalidatedConvert(const nn::Timing& timing) {
953 return Timing{
Lev Proleev8df7d6e2021-04-14 20:54:27 +0100954 .timeOnDeviceNs = NN_TRY(unvalidatedConvert(timing.timeOnDevice)),
955 .timeInDriverNs = NN_TRY(unvalidatedConvert(timing.timeInDriver)),
Lev Proleev900c28a2021-01-26 19:40:20 +0000956 };
957}
958
959nn::GeneralResult<int64_t> unvalidatedConvert(const nn::Duration& duration) {
Michael Butler382d5132021-03-18 21:15:09 -0700960 if (duration < nn::Duration::zero()) {
961 return NN_ERROR() << "Unable to convert invalid (negative) duration";
Lev Proleev900c28a2021-01-26 19:40:20 +0000962 }
Michael Butler382d5132021-03-18 21:15:09 -0700963 constexpr std::chrono::nanoseconds::rep kIntMax = std::numeric_limits<int64_t>::max();
964 const auto count = duration.count();
965 return static_cast<int64_t>(std::min(count, kIntMax));
Lev Proleev900c28a2021-01-26 19:40:20 +0000966}
967
968nn::GeneralResult<int64_t> unvalidatedConvert(const nn::OptionalDuration& optionalDuration) {
969 if (!optionalDuration.has_value()) {
970 return kNoTiming;
971 }
972 return unvalidatedConvert(optionalDuration.value());
973}
974
975nn::GeneralResult<int64_t> unvalidatedConvert(const nn::OptionalTimePoint& optionalTimePoint) {
976 if (!optionalTimePoint.has_value()) {
977 return kNoTiming;
978 }
979 return unvalidatedConvert(optionalTimePoint->time_since_epoch());
980}
981
982nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvert(const nn::SyncFence& syncFence) {
983 auto duplicatedFd = NN_TRY(nn::dupFd(syncFence.getFd()));
984 return ndk::ScopedFileDescriptor(duplicatedFd.release());
985}
986
Michael Butlere52a77e2021-06-07 13:10:58 -0700987nn::GeneralResult<ndk::ScopedFileDescriptor> unvalidatedConvert(const nn::SharedHandle& handle) {
988 auto duplicatedFd = NN_TRY(nn::dupFd(handle->get()));
Lev Proleev900c28a2021-01-26 19:40:20 +0000989 return ndk::ScopedFileDescriptor(duplicatedFd.release());
990}
991
992nn::GeneralResult<std::vector<uint8_t>> convert(const nn::CacheToken& cacheToken) {
Michael Butler388bceb2021-02-03 15:15:43 -0800993 return validatedConvert(cacheToken);
Lev Proleev900c28a2021-01-26 19:40:20 +0000994}
995
996nn::GeneralResult<BufferDesc> convert(const nn::BufferDesc& bufferDesc) {
997 return validatedConvert(bufferDesc);
998}
999
1000nn::GeneralResult<bool> convert(const nn::MeasureTiming& measureTiming) {
1001 return validatedConvert(measureTiming);
1002}
1003
Michael Butlerfadeb8a2021-02-07 00:11:13 -08001004nn::GeneralResult<Memory> convert(const nn::SharedMemory& memory) {
Lev Proleev6b6dfcd2020-11-11 18:28:50 +00001005 return validatedConvert(memory);
1006}
1007
1008nn::GeneralResult<ErrorStatus> convert(const nn::ErrorStatus& errorStatus) {
1009 return validatedConvert(errorStatus);
1010}
1011
Lev Proleev900c28a2021-01-26 19:40:20 +00001012nn::GeneralResult<ExecutionPreference> convert(const nn::ExecutionPreference& executionPreference) {
1013 return validatedConvert(executionPreference);
1014}
1015
1016nn::GeneralResult<Model> convert(const nn::Model& model) {
1017 return validatedConvert(model);
1018}
1019
1020nn::GeneralResult<Priority> convert(const nn::Priority& priority) {
1021 return validatedConvert(priority);
1022}
1023
1024nn::GeneralResult<Request> convert(const nn::Request& request) {
1025 return validatedConvert(request);
1026}
1027
1028nn::GeneralResult<Timing> convert(const nn::Timing& timing) {
1029 return validatedConvert(timing);
1030}
1031
1032nn::GeneralResult<int64_t> convert(const nn::OptionalDuration& optionalDuration) {
1033 return validatedConvert(optionalDuration);
1034}
1035
1036nn::GeneralResult<int64_t> convert(const nn::OptionalTimePoint& outputShapes) {
1037 return validatedConvert(outputShapes);
1038}
1039
1040nn::GeneralResult<std::vector<BufferRole>> convert(const std::vector<nn::BufferRole>& bufferRoles) {
1041 return validatedConvert(bufferRoles);
1042}
1043
Lev Proleev6b6dfcd2020-11-11 18:28:50 +00001044nn::GeneralResult<std::vector<OutputShape>> convert(
1045 const std::vector<nn::OutputShape>& outputShapes) {
1046 return validatedConvert(outputShapes);
1047}
1048
Lev Proleev900c28a2021-01-26 19:40:20 +00001049nn::GeneralResult<std::vector<ndk::ScopedFileDescriptor>> convert(
1050 const std::vector<nn::SharedHandle>& cacheHandles) {
Michael Butlere52a77e2021-06-07 13:10:58 -07001051 return validatedConvert(cacheHandles);
Lev Proleev900c28a2021-01-26 19:40:20 +00001052}
1053
1054nn::GeneralResult<std::vector<ndk::ScopedFileDescriptor>> convert(
1055 const std::vector<nn::SyncFence>& syncFences) {
Michael Butler388bceb2021-02-03 15:15:43 -08001056 return validatedConvert(syncFences);
Lev Proleev900c28a2021-01-26 19:40:20 +00001057}
1058
Lev Proleev6b6dfcd2020-11-11 18:28:50 +00001059nn::GeneralResult<std::vector<int32_t>> toSigned(const std::vector<uint32_t>& vec) {
1060 if (!std::all_of(vec.begin(), vec.end(),
1061 [](uint32_t v) { return v <= std::numeric_limits<int32_t>::max(); })) {
1062 return NN_ERROR() << "Vector contains a value that doesn't fit into int32_t.";
1063 }
1064 return std::vector<int32_t>(vec.begin(), vec.end());
1065}
1066
1067} // namespace aidl::android::hardware::neuralnetworks::utils