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