blob: 83e0015689f5b90c94ceb955d273385ae41d2a97 [file] [log] [blame]
Michael Butler4b276a72020-08-06 23:22:35 -07001/*
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 "Callbacks.h"
20#include "Conversions.h"
21#include "Utils.h"
22
23#include <android/hardware/neuralnetworks/1.0/IDevice.h>
24#include <android/hardware/neuralnetworks/1.0/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/CommonUtils.h>
32#include <nnapi/hal/HandleError.h>
33#include <nnapi/hal/ProtectCallback.h>
34
35#include <functional>
36#include <memory>
37#include <optional>
38#include <string>
39#include <vector>
40
Michael Butleraad934b2020-12-13 23:06:06 -080041// See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
42// lifetimes across processes and for protecting asynchronous calls across HIDL.
43
Michael Butler4b276a72020-08-06 23:22:35 -070044namespace android::hardware::neuralnetworks::V1_0::utils {
45namespace {
46
47nn::GeneralResult<nn::Capabilities> initCapabilities(V1_0::IDevice* device) {
48 CHECK(device != nullptr);
49
50 nn::GeneralResult<nn::Capabilities> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
51 << "uninitialized";
52 const auto cb = [&result](ErrorStatus status, const Capabilities& capabilities) {
53 if (status != ErrorStatus::NONE) {
Michael Butler6547b2a2020-11-22 19:36:30 -080054 const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
Michael Butler4b276a72020-08-06 23:22:35 -070055 result = NN_ERROR(canonical) << "getCapabilities failed with " << toString(status);
56 } else {
Michael Butler6547b2a2020-11-22 19:36:30 -080057 result = nn::convert(capabilities);
Michael Butler4b276a72020-08-06 23:22:35 -070058 }
59 };
60
61 const auto ret = device->getCapabilities(cb);
Michael Butlercca3e202020-11-22 20:25:34 -080062 HANDLE_TRANSPORT_FAILURE(ret);
Michael Butler4b276a72020-08-06 23:22:35 -070063
64 return result;
65}
66
67} // namespace
68
69nn::GeneralResult<std::shared_ptr<const Device>> Device::create(std::string name,
70 sp<V1_0::IDevice> device) {
71 if (name.empty()) {
72 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
73 << "V1_0::utils::Device::create must have non-empty name";
74 }
75 if (device == nullptr) {
76 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT)
77 << "V1_0::utils::Device::create must have non-null device";
78 }
79
80 auto capabilities = NN_TRY(initCapabilities(device.get()));
81
82 auto deathHandler = NN_TRY(hal::utils::DeathHandler::create(device));
83 return std::make_shared<const Device>(PrivateConstructorTag{}, std::move(name),
84 std::move(capabilities), std::move(device),
85 std::move(deathHandler));
86}
87
88Device::Device(PrivateConstructorTag /*tag*/, std::string name, nn::Capabilities capabilities,
89 sp<V1_0::IDevice> device, hal::utils::DeathHandler deathHandler)
90 : kName(std::move(name)),
91 kCapabilities(std::move(capabilities)),
92 kDevice(std::move(device)),
93 kDeathHandler(std::move(deathHandler)) {}
94
95const std::string& Device::getName() const {
96 return kName;
97}
98
99const std::string& Device::getVersionString() const {
100 return kVersionString;
101}
102
103nn::Version Device::getFeatureLevel() const {
104 return nn::Version::ANDROID_OC_MR1;
105}
106
107nn::DeviceType Device::getType() const {
108 return nn::DeviceType::OTHER;
109}
110
111const std::vector<nn::Extension>& Device::getSupportedExtensions() const {
112 return kExtensions;
113}
114
115const nn::Capabilities& Device::getCapabilities() const {
116 return kCapabilities;
117}
118
119std::pair<uint32_t, uint32_t> Device::getNumberOfCacheFilesNeeded() const {
120 return std::make_pair(/*numModelCache=*/0, /*numDataCache=*/0);
121}
122
123nn::GeneralResult<void> Device::wait() const {
124 const auto ret = kDevice->ping();
Michael Butlercca3e202020-11-22 20:25:34 -0800125 HANDLE_TRANSPORT_FAILURE(ret);
126 return {};
Michael Butler4b276a72020-08-06 23:22:35 -0700127}
128
129nn::GeneralResult<std::vector<bool>> Device::getSupportedOperations(const nn::Model& model) const {
130 // Ensure that model is ready for IPC.
131 std::optional<nn::Model> maybeModelInShared;
132 const nn::Model& modelInShared =
133 NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
134
135 const auto hidlModel = NN_TRY(convert(modelInShared));
136
137 nn::GeneralResult<std::vector<bool>> result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
138 << "uninitialized";
139 auto cb = [&result, &model](ErrorStatus status, const hidl_vec<bool>& supportedOperations) {
140 if (status != ErrorStatus::NONE) {
Michael Butler6547b2a2020-11-22 19:36:30 -0800141 const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
Michael Butler4b276a72020-08-06 23:22:35 -0700142 result = NN_ERROR(canonical)
143 << "getSupportedOperations failed with " << toString(status);
144 } else if (supportedOperations.size() != model.main.operations.size()) {
145 result = NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
146 << "getSupportedOperations returned vector of size "
147 << supportedOperations.size() << " but expected "
148 << model.main.operations.size();
149 } else {
150 result = supportedOperations;
151 }
152 };
153
154 const auto ret = kDevice->getSupportedOperations(hidlModel, cb);
Michael Butlercca3e202020-11-22 20:25:34 -0800155 HANDLE_TRANSPORT_FAILURE(ret);
Michael Butler4b276a72020-08-06 23:22:35 -0700156
157 return result;
158}
159
160nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModel(
161 const nn::Model& model, nn::ExecutionPreference /*preference*/, nn::Priority /*priority*/,
Slava Shklyaev49817a02020-10-27 18:44:01 +0000162 nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
163 const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
Michael Butler4b276a72020-08-06 23:22:35 -0700164 // Ensure that model is ready for IPC.
165 std::optional<nn::Model> maybeModelInShared;
166 const nn::Model& modelInShared =
167 NN_TRY(hal::utils::flushDataFromPointerToShared(&model, &maybeModelInShared));
168
169 const auto hidlModel = NN_TRY(convert(modelInShared));
170
171 const auto cb = sp<PreparedModelCallback>::make();
172 const auto scoped = kDeathHandler.protectCallback(cb.get());
173
174 const auto ret = kDevice->prepareModel(hidlModel, cb);
Michael Butlercca3e202020-11-22 20:25:34 -0800175 const auto status = HANDLE_TRANSPORT_FAILURE(ret);
Michael Butler4b276a72020-08-06 23:22:35 -0700176 if (status != ErrorStatus::NONE) {
Michael Butler6547b2a2020-11-22 19:36:30 -0800177 const auto canonical = nn::convert(status).value_or(nn::ErrorStatus::GENERAL_FAILURE);
Michael Butler4b276a72020-08-06 23:22:35 -0700178 return NN_ERROR(canonical) << "prepareModel failed with " << toString(status);
179 }
180
181 return cb->get();
182}
183
184nn::GeneralResult<nn::SharedPreparedModel> Device::prepareModelFromCache(
Slava Shklyaev49817a02020-10-27 18:44:01 +0000185 nn::OptionalTimePoint /*deadline*/, const std::vector<nn::SharedHandle>& /*modelCache*/,
186 const std::vector<nn::SharedHandle>& /*dataCache*/, const nn::CacheToken& /*token*/) const {
Michael Butler4b276a72020-08-06 23:22:35 -0700187 return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
188 << "IDevice::prepareModelFromCache not supported on 1.0 HAL service";
189}
190
191nn::GeneralResult<nn::SharedBuffer> Device::allocate(
192 const nn::BufferDesc& /*desc*/,
193 const std::vector<nn::SharedPreparedModel>& /*preparedModels*/,
194 const std::vector<nn::BufferRole>& /*inputRoles*/,
195 const std::vector<nn::BufferRole>& /*outputRoles*/) const {
196 return NN_ERROR(nn::ErrorStatus::GENERAL_FAILURE)
197 << "IDevice::allocate not supported on 1.0 HAL service";
198}
199
200} // namespace android::hardware::neuralnetworks::V1_0::utils