/* * Copyright (C) 2021 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "Utils.h" #include #include #include #include #include #include #include namespace aidl::android::hardware::neuralnetworks::utils { namespace { nn::GeneralResult clone(const ndk::ScopedFileDescriptor& fd); using utils::clone; template nn::GeneralResult> cloneVec(const std::vector& arguments) { std::vector clonedObjects; clonedObjects.reserve(arguments.size()); for (const auto& argument : arguments) { clonedObjects.push_back(NN_TRY(clone(argument))); } return clonedObjects; } template nn::GeneralResult> clone(const std::vector& arguments) { return cloneVec(arguments); } nn::GeneralResult clone(const ndk::ScopedFileDescriptor& fd) { auto duplicatedFd = NN_TRY(nn::dupFd(fd.get())); return ndk::ScopedFileDescriptor(duplicatedFd.release()); } nn::GeneralResult clone(const common::NativeHandle& handle) { return common::NativeHandle{ .fds = NN_TRY(cloneVec(handle.fds)), .ints = handle.ints, }; } } // namespace nn::GeneralResult clone(const Memory& memory) { switch (memory.getTag()) { case Memory::Tag::ashmem: { const auto& ashmem = memory.get(); auto handle = common::Ashmem{ .fd = NN_TRY(clone(ashmem.fd)), .size = ashmem.size, }; return Memory::make(std::move(handle)); } case Memory::Tag::mappableFile: { const auto& memFd = memory.get(); auto handle = common::MappableFile{ .length = memFd.length, .prot = memFd.prot, .fd = NN_TRY(clone(memFd.fd)), .offset = memFd.offset, }; return Memory::make(std::move(handle)); } case Memory::Tag::hardwareBuffer: { const auto& hardwareBuffer = memory.get(); auto handle = graphics::common::HardwareBuffer{ .description = hardwareBuffer.description, .handle = NN_TRY(clone(hardwareBuffer.handle)), }; return Memory::make(std::move(handle)); } } return (NN_ERROR() << "Unrecognized Memory::Tag: " << memory.getTag()) . operator nn::GeneralResult(); } nn::GeneralResult clone(const RequestMemoryPool& requestPool) { using Tag = RequestMemoryPool::Tag; switch (requestPool.getTag()) { case Tag::pool: return RequestMemoryPool::make(NN_TRY(clone(requestPool.get()))); case Tag::token: return RequestMemoryPool::make(requestPool.get()); } // Using explicit type conversion because std::variant inside the RequestMemoryPool confuses the // compiler. return (NN_ERROR() << "Unrecognized request pool tag: " << requestPool.getTag()) . operator nn::GeneralResult(); } nn::GeneralResult clone(const Request& request) { return Request{ .inputs = request.inputs, .outputs = request.outputs, .pools = NN_TRY(clone(request.pools)), }; } nn::GeneralResult clone(const Model& model) { return Model{ .main = model.main, .referenced = model.referenced, .operandValues = model.operandValues, .pools = NN_TRY(clone(model.pools)), .relaxComputationFloat32toFloat16 = model.relaxComputationFloat32toFloat16, .extensionNameToPrefix = model.extensionNameToPrefix, }; } nn::GeneralResult handleTransportError(const ndk::ScopedAStatus& ret) { if (ret.getStatus() == STATUS_DEAD_OBJECT) { return nn::error(nn::ErrorStatus::DEAD_OBJECT) << "Binder transaction returned STATUS_DEAD_OBJECT: " << ret.getDescription(); } if (ret.isOk()) { return {}; } if (ret.getExceptionCode() != EX_SERVICE_SPECIFIC) { return nn::error(nn::ErrorStatus::GENERAL_FAILURE) << "Binder transaction returned exception: " << ret.getDescription(); } return nn::error(static_cast(ret.getServiceSpecificError())) << ret.getMessage(); } } // namespace aidl::android::hardware::neuralnetworks::utils