1 /*
2  * Copyright (C) 2020 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 "Device.h"
18 
19 #include "Conversions.h"
20 #include "Utils.h"
21 
22 #include <android/hardware/neuralnetworks/1.0/types.h>
23 #include <android/hardware/neuralnetworks/1.1/IDevice.h>
24 #include <android/hardware/neuralnetworks/1.1/types.h>
25 #include <nnapi/IBuffer.h>
26 #include <nnapi/IDevice.h>
27 #include <nnapi/IPreparedModel.h>
28 #include <nnapi/OperandTypes.h>
29 #include <nnapi/Result.h>
30 #include <nnapi/Types.h>
31 #include <nnapi/hal/1.0/Callbacks.h>
32 #include <nnapi/hal/CommonUtils.h>
33 #include <nnapi/hal/HandleError.h>
34 #include <nnapi/hal/ProtectCallback.h>
35 
36 #include <functional>
37 #include <memory>
38 #include <optional>
39 #include <string>
40 #include <vector>
41 
42 // See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
43 // lifetimes across processes and for protecting asynchronous calls across HIDL.
44 
45 namespace android::hardware::neuralnetworks::V1_1::utils {
46 namespace {
47 
capabilitiesCallback(V1_0::ErrorStatus status,const Capabilities & capabilities)48 nn::GeneralResult<nn::Capabilities> capabilitiesCallback(V1_0::ErrorStatus status,
49                                                          const Capabilities& capabilities) {
50     HANDLE_HAL_STATUS(status) << "getting capabilities failed with " << toString(status);
51     return nn::convert(capabilities);
52 }
53 
getCapabilitiesFrom(V1_1::IDevice * device)54 nn::GeneralResult<nn::Capabilities> getCapabilitiesFrom(V1_1::IDevice* device) {
55     CHECK(device != nullptr);
56 
57     auto cb = hal::utils::CallbackValue(capabilitiesCallback);
58 
59     const auto ret = device->getCapabilities_1_1(cb);
60     HANDLE_TRANSPORT_FAILURE(ret);
61 
62     return cb.take();
63 }
64 
65 }  // namespace
66 
create(std::string name,sp<V1_1::IDevice> device)67 nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name,
68                                                                 sp<V1_1::IDevice> device) {
69     if (name.empty()) {
70         return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
71                << "V1_1::utils::Device::create must have non-empty name";
72     }
73     if (device == nullptr) {
74         return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
75                << "V1_1::utils::Device::create must have non-null device";
76     }
77 
78     auto capabilities = NN_TRY(getCapabilitiesFrom(device.get()));
79 
80     auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(device));
81     return std::make_shared<const Device>(PrivateConstructorTag{}, std::move(name),
82                                           std::move(capabilities), std::move(device),
83                                           std::move(deathHandler));
84 }
85 
Device(PrivateConstructorTag,std::string name,nn::Capabilities capabilities,sp<V1_1::IDevice> device,hal::utils::DeathHandler deathHandler)86 Device::Device(PrivateConstructorTag /*tag*/, std::string name, nn::Capabilities capabilities,
87                sp<V1_1::IDevice> device, hal::utils::DeathHandler deathHandler)
88     : kName(std::move(name)),
89       kCapabilities(std::move(capabilities)),
90       kDevice(std::move(device)),
91       kDeathHandler(std::move(deathHandler)) {}
92 
getName() const93 const std::string& Device::getName() const {
94     return kName;
95 }
96 
getVersionString() const97 const std::string& Device::getVersionString() const {
98     return kVersionString;
99 }
100 
getFeatureLevel() const101 nn::Version Device::getFeatureLevel() const {
102     return nn::Version::ANDROID_P;
103 }
104 
getType() const105 nn::DeviceType Device::getType() const {
106     return nn::DeviceType::UNKNOWN;
107 }
108 
getSupportedExtensions() const109 const std::vector<nn::Extension>& Device::getSupportedExtensions() const {
110     return kExtensions;
111 }
112 
getCapabilities() const113 const nn::Capabilities& Device::getCapabilities() const {
114     return kCapabilities;
115 }
116 
getNumberOfCacheFilesNeeded() const117 std::pair<uint32_t, uint32_t> Device::getNumberOfCacheFilesNeeded() const {
118     return std::make_pair(/*numModelCache=*/0, /*numDataCache=*/0);
119 }
120 
wait() const121 nn::GeneralResult<void> Device::wait() const {
122     const auto ret = kDevice->ping();
123     HANDLE_TRANSPORT_FAILURE(ret);
124     return {};
125 }
126 
getSupportedOperations(const nn::Model & model) const127 nn::GeneralResult<std::vector<bool>> Device::getSupportedOperations(const nn::Model& model) const {
128     // Ensure that model is ready for IPC.
129     std::optional<nn::Model> maybeModelInShared;
130     const nn::Model& modelInShared =
131             NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
132 
133     const auto hidlModel = NN_TRY(convert(modelInShared));
134 
135     auto cb = hal::utils::CallbackValue(V1_0::utils::supportedOperationsCallback);
136 
137     const auto ret = kDevice->getSupportedOperations_1_1(hidlModel, cb);
138     HANDLE_TRANSPORT_FAILURE(ret);
139 
140     return cb.take();
141 }
142 
prepareModel(const nn::Model & model,nn::ExecutionPreference preference,nn::Priority,nn::OptionalTimePoint,const std::vector<nn::SharedHandle> &,const std::vector<nn::SharedHandle> &,const nn::CacheToken &) const143 nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
144         const nn::Model& model, nn::ExecutionPreference preference, nn::Priority /*priority*/,
145         nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
146         const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
147     // Ensure that model is ready for IPC.
148     std::optional<nn::Model> maybeModelInShared;
149     const nn::Model& modelInShared =
150             NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
151 
152     const auto hidlModel = NN_TRY(convert(modelInShared));
153     const auto hidlPreference = NN_TRY(convert(preference));
154 
155     const auto cb = sp<V1_0::utils::PreparedModelCallback>::make();
156     const auto scoped = kDeathHandler.protectCallback(cb.get());
157 
158     const auto ret = kDevice->prepareModel_1_1(hidlModel, hidlPreference, cb);
159     const auto status = HANDLE_TRANSPORT_FAILURE(ret);
160     HANDLE_HAL_STATUS(status) << "model preparation failed with " << toString(status);
161 
162     return cb->get();
163 }
164 
prepareModelFromCache(nn::OptionalTimePoint,const std::vector<nn::SharedHandle> &,const std::vector<nn::SharedHandle> &,const nn::CacheToken &) const165 nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModelFromCache(
166         nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
167         const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
168     return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
169            << "IDevice::prepareModelFromCache not supported on 1.1 HAL service";
170 }
171 
allocate(const nn::BufferDesc &,const std::vector<nn::SharedPreparedModel> &,const std::vector<nn::BufferRole> &,const std::vector<nn::BufferRole> &) const172 nn::GeneralResult<nn::SharedBuffer> Device::allocate(
173         const nn::BufferDesc& /*desc*/,
174         const std::vector<nn::SharedPreparedModel>& /*preparedModels*/,
175         const std::vector<nn::BufferRole>& /*inputRoles*/,
176         const std::vector<nn::BufferRole>& /*outputRoles*/) const {
177     return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
178            << "IDevice::allocate not supported on 1.1 HAL service";
179 }
180 
181 }  // namespace android::hardware::neuralnetworks::V1_1::utils
182