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 "Buffer.h"
20 #include "PreparedModel.h"
21
22 #include <android-base/logging.h>
23 #include <android/hardware/neuralnetworks/1.0/IPreparedModelCallback.h>
24 #include <android/hardware/neuralnetworks/1.0/types.h>
25 #include <android/hardware/neuralnetworks/1.1/types.h>
26 #include <android/hardware/neuralnetworks/1.2/IPreparedModelCallback.h>
27 #include <android/hardware/neuralnetworks/1.2/types.h>
28 #include <android/hardware/neuralnetworks/1.3/IDevice.h>
29 #include <android/hardware/neuralnetworks/1.3/IPreparedModelCallback.h>
30 #include <android/hardware/neuralnetworks/1.3/types.h>
31 #include <hwbinder/IPCThreadState.h>
32 #include <nnapi/IBuffer.h>
33 #include <nnapi/IDevice.h>
34 #include <nnapi/IPreparedModel.h>
35 #include <nnapi/Result.h>
36 #include <nnapi/TypeUtils.h>
37 #include <nnapi/Types.h>
38 #include <nnapi/hal/1.0/Conversions.h>
39 #include <nnapi/hal/1.0/Utils.h>
40 #include <nnapi/hal/1.1/Conversions.h>
41 #include <nnapi/hal/1.1/Utils.h>
42 #include <nnapi/hal/1.2/Conversions.h>
43 #include <nnapi/hal/1.2/Utils.h>
44 #include <nnapi/hal/1.3/Conversions.h>
45 #include <nnapi/hal/1.3/Utils.h>
46 #include <sys/types.h>
47
48 #include <memory>
49
50 // See hardware/interfaces/neuralnetworks/utils/README.md for more information on HIDL interface
51 // lifetimes across processes and for protecting asynchronous calls across HIDL.
52
53 namespace android::hardware::neuralnetworks::adapter {
54 namespace {
55
56 template <typename Type>
convertInput(const Type & object)57 auto convertInput(const Type& object) -> decltype(nn::convert(std::declval<Type>())) {
58 auto result = nn::convert(object);
59 if (!result.has_value()) {
60 result.error().code = nn::ErrorStatus::INVALID_ARGUMENT;
61 }
62 return result;
63 }
64
65 using PrepareModelResult = nn::GeneralResult<nn::SharedPreparedModel>;
66
adaptPreparedModel(nn::SharedPreparedModel preparedModel,Executor executor,uid_t userId)67 sp<PreparedModel> adaptPreparedModel(nn::SharedPreparedModel preparedModel, Executor executor,
68 uid_t userId) {
69 if (preparedModel == nullptr) {
70 return nullptr;
71 }
72 return sp<PreparedModel>::make(std::move(preparedModel), std::move(executor), userId);
73 }
74
notify(V1_0::IPreparedModelCallback * callback,nn::ErrorStatus status,const sp<PreparedModel> & hidlPreparedModel)75 void notify(V1_0::IPreparedModelCallback* callback, nn::ErrorStatus status,
76 const sp<PreparedModel>& hidlPreparedModel) {
77 if (callback != nullptr) {
78 const auto hidlStatus = V1_0::utils::convert(status).value();
79 const auto ret = callback->notify(hidlStatus, hidlPreparedModel);
80 if (!ret.isOk()) {
81 LOG(ERROR) << "V1_0::IPreparedModelCallback::notify failed with " << ret.description();
82 }
83 }
84 }
85
notify(V1_2::IPreparedModelCallback * callback,nn::ErrorStatus status,const sp<PreparedModel> & hidlPreparedModel)86 void notify(V1_2::IPreparedModelCallback* callback, nn::ErrorStatus status,
87 const sp<PreparedModel>& hidlPreparedModel) {
88 if (callback != nullptr) {
89 const auto hidlStatus = V1_2::utils::convert(status).value();
90 const auto ret = callback->notify_1_2(hidlStatus, hidlPreparedModel);
91 if (!ret.isOk()) {
92 LOG(ERROR) << "V1_2::IPreparedModelCallback::notify_1_2 failed with "
93 << ret.description();
94 }
95 }
96 }
97
notify(V1_3::IPreparedModelCallback * callback,nn::ErrorStatus status,const sp<PreparedModel> & hidlPreparedModel)98 void notify(V1_3::IPreparedModelCallback* callback, nn::ErrorStatus status,
99 const sp<PreparedModel>& hidlPreparedModel) {
100 if (callback != nullptr) {
101 const auto hidlStatus = V1_3::utils::convert(status).value();
102 const auto ret = callback->notify_1_3(hidlStatus, hidlPreparedModel);
103 if (!ret.isOk()) {
104 LOG(ERROR) << "V1_3::IPreparedModelCallback::notify_1_3 failed with "
105 << ret.description();
106 }
107 }
108 }
109
110 template <typename CallbackType>
notify(CallbackType * callback,PrepareModelResult result,Executor executor,uid_t userId)111 void notify(CallbackType* callback, PrepareModelResult result, Executor executor, uid_t userId) {
112 if (!result.has_value()) {
113 const auto [message, status] = std::move(result).error();
114 LOG(ERROR) << message;
115 notify(callback, status, nullptr);
116 } else {
117 auto preparedModel = std::move(result).value();
118 auto hidlPreparedModel =
119 adaptPreparedModel(std::move(preparedModel), std::move(executor), userId);
120 notify(callback, nn::ErrorStatus::NONE, std::move(hidlPreparedModel));
121 }
122 }
123
124 template <typename ModelType>
getSupportedOperations(const nn::SharedDevice & device,const ModelType & model)125 nn::GeneralResult<hidl_vec<bool>> getSupportedOperations(const nn::SharedDevice& device,
126 const ModelType& model) {
127 const auto nnModel = NN_TRY(convertInput(model));
128 return NN_TRY(device->getSupportedOperations(nnModel));
129 }
130
prepareModel(const nn::SharedDevice & device,const Executor & executor,const V1_0::Model & model,const sp<V1_0::IPreparedModelCallback> & callback)131 nn::GeneralResult<void> prepareModel(const nn::SharedDevice& device, const Executor& executor,
132 const V1_0::Model& model,
133 const sp<V1_0::IPreparedModelCallback>& callback) {
134 if (callback.get() == nullptr) {
135 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
136 }
137
138 auto nnModel = NN_TRY(convertInput(model));
139
140 const uid_t userId = hardware::IPCThreadState::self()->getCallingUid();
141 Task task = [device, nnModel = std::move(nnModel), userId, executor, callback] {
142 auto result = device->prepareModel(nnModel, nn::ExecutionPreference::DEFAULT,
143 nn::Priority::DEFAULT, {}, {}, {}, {});
144 notify(callback.get(), std::move(result), executor, userId);
145 };
146 executor(std::move(task), userId, {});
147
148 return {};
149 }
150
prepareModel_1_1(const nn::SharedDevice & device,const Executor & executor,const V1_1::Model & model,V1_1::ExecutionPreference preference,const sp<V1_0::IPreparedModelCallback> & callback)151 nn::GeneralResult<void> prepareModel_1_1(const nn::SharedDevice& device, const Executor& executor,
152 const V1_1::Model& model,
153 V1_1::ExecutionPreference preference,
154 const sp<V1_0::IPreparedModelCallback>& callback) {
155 if (callback.get() == nullptr) {
156 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
157 }
158
159 auto nnModel = NN_TRY(convertInput(model));
160 const auto nnPreference = NN_TRY(convertInput(preference));
161
162 const uid_t userId = hardware::IPCThreadState::self()->getCallingUid();
163 Task task = [device, nnModel = std::move(nnModel), nnPreference, userId, executor, callback] {
164 auto result =
165 device->prepareModel(nnModel, nnPreference, nn::Priority::DEFAULT, {}, {}, {}, {});
166 notify(callback.get(), std::move(result), executor, userId);
167 };
168 executor(std::move(task), userId, {});
169
170 return {};
171 }
172
prepareModel_1_2(const nn::SharedDevice & device,const Executor & executor,const V1_2::Model & model,V1_1::ExecutionPreference preference,const hidl_vec<hidl_handle> & modelCache,const hidl_vec<hidl_handle> & dataCache,const CacheToken & token,const sp<V1_2::IPreparedModelCallback> & callback)173 nn::GeneralResult<void> prepareModel_1_2(const nn::SharedDevice& device, const Executor& executor,
174 const V1_2::Model& model,
175 V1_1::ExecutionPreference preference,
176 const hidl_vec<hidl_handle>& modelCache,
177 const hidl_vec<hidl_handle>& dataCache,
178 const CacheToken& token,
179 const sp<V1_2::IPreparedModelCallback>& callback) {
180 if (callback.get() == nullptr) {
181 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
182 }
183
184 auto nnModel = NN_TRY(convertInput(model));
185 const auto nnPreference = NN_TRY(convertInput(preference));
186 auto nnModelCache = NN_TRY(convertInput(modelCache));
187 auto nnDataCache = NN_TRY(convertInput(dataCache));
188 const auto nnToken = nn::CacheToken(token);
189
190 const uid_t userId = hardware::IPCThreadState::self()->getCallingUid();
191 Task task = [device, nnModel = std::move(nnModel), nnPreference,
192 nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
193 nnToken, userId, executor, callback] {
194 auto result = device->prepareModel(nnModel, nnPreference, nn::Priority::DEFAULT, {},
195 nnModelCache, nnDataCache, nnToken);
196 notify(callback.get(), std::move(result), executor, userId);
197 };
198 executor(std::move(task), userId, {});
199
200 return {};
201 }
202
prepareModel_1_3(const nn::SharedDevice & device,const Executor & executor,const V1_3::Model & model,V1_1::ExecutionPreference preference,V1_3::Priority priority,const V1_3::OptionalTimePoint & deadline,const hidl_vec<hidl_handle> & modelCache,const hidl_vec<hidl_handle> & dataCache,const CacheToken & token,const sp<V1_3::IPreparedModelCallback> & callback)203 nn::GeneralResult<void> prepareModel_1_3(
204 const nn::SharedDevice& device, const Executor& executor, const V1_3::Model& model,
205 V1_1::ExecutionPreference preference, V1_3::Priority priority,
206 const V1_3::OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache,
207 const hidl_vec<hidl_handle>& dataCache, const CacheToken& token,
208 const sp<V1_3::IPreparedModelCallback>& callback) {
209 if (callback.get() == nullptr) {
210 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
211 }
212
213 auto nnModel = NN_TRY(convertInput(model));
214 const auto nnPreference = NN_TRY(convertInput(preference));
215 const auto nnPriority = NN_TRY(convertInput(priority));
216 const auto nnDeadline = NN_TRY(convertInput(deadline));
217 auto nnModelCache = NN_TRY(convertInput(modelCache));
218 auto nnDataCache = NN_TRY(convertInput(dataCache));
219 const auto nnToken = nn::CacheToken(token);
220
221 const uid_t userId = hardware::IPCThreadState::self()->getCallingUid();
222 Task task = [device, nnModel = std::move(nnModel), nnPreference, nnPriority, nnDeadline,
223 nnModelCache = std::move(nnModelCache), nnDataCache = std::move(nnDataCache),
224 nnToken, userId, executor, callback] {
225 auto result = device->prepareModel(nnModel, nnPreference, nnPriority, nnDeadline,
226 nnModelCache, nnDataCache, nnToken);
227 notify(callback.get(), std::move(result), executor, userId);
228 };
229 executor(std::move(task), userId, nnDeadline);
230
231 return {};
232 }
233
prepareModelFromCache(const nn::SharedDevice & device,const Executor & executor,const hidl_vec<hidl_handle> & modelCache,const hidl_vec<hidl_handle> & dataCache,const CacheToken & token,const sp<V1_2::IPreparedModelCallback> & callback)234 nn::GeneralResult<void> prepareModelFromCache(const nn::SharedDevice& device,
235 const Executor& executor,
236 const hidl_vec<hidl_handle>& modelCache,
237 const hidl_vec<hidl_handle>& dataCache,
238 const CacheToken& token,
239 const sp<V1_2::IPreparedModelCallback>& callback) {
240 if (callback.get() == nullptr) {
241 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
242 }
243
244 auto nnModelCache = NN_TRY(convertInput(modelCache));
245 auto nnDataCache = NN_TRY(convertInput(dataCache));
246 const auto nnToken = nn::CacheToken(token);
247
248 const uid_t userId = hardware::IPCThreadState::self()->getCallingUid();
249 Task task = [device, nnModelCache = std::move(nnModelCache),
250 nnDataCache = std::move(nnDataCache), nnToken, userId, executor, callback] {
251 auto result = device->prepareModelFromCache({}, nnModelCache, nnDataCache, nnToken);
252 notify(callback.get(), std::move(result), executor, userId);
253 };
254 executor(std::move(task), userId, {});
255
256 return {};
257 }
258
prepareModelFromCache_1_3(const nn::SharedDevice & device,const Executor & executor,const V1_3::OptionalTimePoint & deadline,const hidl_vec<hidl_handle> & modelCache,const hidl_vec<hidl_handle> & dataCache,const CacheToken & token,const sp<V1_3::IPreparedModelCallback> & callback)259 nn::GeneralResult<void> prepareModelFromCache_1_3(
260 const nn::SharedDevice& device, const Executor& executor,
261 const V1_3::OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache,
262 const hidl_vec<hidl_handle>& dataCache, const CacheToken& token,
263 const sp<V1_3::IPreparedModelCallback>& callback) {
264 if (callback.get() == nullptr) {
265 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Invalid callback";
266 }
267
268 const auto nnDeadline = NN_TRY(convertInput(deadline));
269 auto nnModelCache = NN_TRY(convertInput(modelCache));
270 auto nnDataCache = NN_TRY(convertInput(dataCache));
271 const auto nnToken = nn::CacheToken(token);
272
273 const uid_t userId = hardware::IPCThreadState::self()->getCallingUid();
274 auto task = [device, nnDeadline, nnModelCache = std::move(nnModelCache),
275 nnDataCache = std::move(nnDataCache), nnToken, userId, executor, callback] {
276 auto result = device->prepareModelFromCache(nnDeadline, nnModelCache, nnDataCache, nnToken);
277 notify(callback.get(), std::move(result), executor, userId);
278 };
279 executor(std::move(task), userId, nnDeadline);
280
281 return {};
282 }
283
downcast(const sp<V1_3::IPreparedModel> & preparedModel)284 nn::GeneralResult<nn::SharedPreparedModel> downcast(const sp<V1_3::IPreparedModel>& preparedModel) {
285 if (preparedModel == nullptr) {
286 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "preparedModel is nullptr";
287 }
288 if (preparedModel->isRemote()) {
289 return NN_ERROR(nn::ErrorStatus::INVALID_ARGUMENT) << "Cannot convert remote models";
290 }
291
292 // This static_cast is safe because adapter::PreparedModel is the only class that implements
293 // the IPreparedModel interface in the adapter service code.
294 const auto* casted = static_cast<const PreparedModel*>(preparedModel.get());
295 return casted->getUnderlyingPreparedModel();
296 }
297
downcastAll(const hidl_vec<sp<V1_3::IPreparedModel>> & preparedModels)298 nn::GeneralResult<std::vector<nn::SharedPreparedModel>> downcastAll(
299 const hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels) {
300 std::vector<nn::SharedPreparedModel> canonical;
301 canonical.reserve(preparedModels.size());
302 for (const auto& preparedModel : preparedModels) {
303 canonical.push_back(NN_TRY(downcast(preparedModel)));
304 }
305 return canonical;
306 }
307
allocate(const nn::SharedDevice & device,const V1_3::BufferDesc & desc,const hidl_vec<sp<V1_3::IPreparedModel>> & preparedModels,const hidl_vec<V1_3::BufferRole> & inputRoles,const hidl_vec<V1_3::BufferRole> & outputRoles)308 nn::GeneralResult<std::pair<sp<V1_3::IBuffer>, uint32_t>> allocate(
309 const nn::SharedDevice& device, const V1_3::BufferDesc& desc,
310 const hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels,
311 const hidl_vec<V1_3::BufferRole>& inputRoles,
312 const hidl_vec<V1_3::BufferRole>& outputRoles) {
313 auto nnDesc = NN_TRY(convertInput(desc));
314 auto nnPreparedModels = NN_TRY(downcastAll(preparedModels));
315 auto nnInputRoles = NN_TRY(convertInput(inputRoles));
316 auto nnOutputRoles = NN_TRY(convertInput(outputRoles));
317
318 auto buffer = NN_TRY(device->allocate(nnDesc, nnPreparedModels, nnInputRoles, nnOutputRoles));
319
320 const nn::Request::MemoryDomainToken token = buffer->getToken();
321 auto hidlBuffer = sp<Buffer>::make(std::move(buffer));
322 return std::make_pair(std::move(hidlBuffer), static_cast<uint32_t>(token));
323 }
324
325 } // namespace
326
Device(nn::SharedDevice device,Executor executor)327 Device::Device(nn::SharedDevice device, Executor executor)
328 : kDevice(std::move(device)), kExecutor(std::move(executor)) {
329 CHECK(kDevice != nullptr);
330 CHECK(kExecutor != nullptr);
331 }
332
getCapabilities(getCapabilities_cb cb)333 Return<void> Device::getCapabilities(getCapabilities_cb cb) {
334 const auto capabilities = V1_0::utils::convert(kDevice->getCapabilities()).value();
335 cb(V1_0::ErrorStatus::NONE, capabilities);
336 return Void();
337 }
338
getCapabilities_1_1(getCapabilities_1_1_cb cb)339 Return<void> Device::getCapabilities_1_1(getCapabilities_1_1_cb cb) {
340 const auto capabilities = V1_1::utils::convert(kDevice->getCapabilities()).value();
341 cb(V1_0::ErrorStatus::NONE, capabilities);
342 return Void();
343 }
344
getCapabilities_1_2(getCapabilities_1_2_cb cb)345 Return<void> Device::getCapabilities_1_2(getCapabilities_1_2_cb cb) {
346 const auto capabilities = V1_2::utils::convert(kDevice->getCapabilities()).value();
347 cb(V1_0::ErrorStatus::NONE, capabilities);
348 return Void();
349 }
350
getCapabilities_1_3(getCapabilities_1_3_cb cb)351 Return<void> Device::getCapabilities_1_3(getCapabilities_1_3_cb cb) {
352 const auto capabilities = V1_3::utils::convert(kDevice->getCapabilities()).value();
353 cb(V1_3::ErrorStatus::NONE, capabilities);
354 return Void();
355 }
356
getVersionString(getVersionString_cb cb)357 Return<void> Device::getVersionString(getVersionString_cb cb) {
358 cb(V1_0::ErrorStatus::NONE, kDevice->getVersionString());
359 return Void();
360 }
361
getType(getType_cb cb)362 Return<void> Device::getType(getType_cb cb) {
363 const auto maybeDeviceType = V1_2::utils::convert(kDevice->getType());
364 if (!maybeDeviceType.has_value()) {
365 const auto& [message, code] = maybeDeviceType.error();
366 LOG(ERROR) << "adapter::Device::getType failed with " << code << ": " << message;
367 cb(V1_2::utils::convert(code).value(), {});
368 } else {
369 cb(V1_0::ErrorStatus::NONE, maybeDeviceType.value());
370 }
371 return Void();
372 }
373
getSupportedExtensions(getSupportedExtensions_cb cb)374 Return<void> Device::getSupportedExtensions(getSupportedExtensions_cb cb) {
375 const auto maybeSupportedExtensions = V1_2::utils::convert(kDevice->getSupportedExtensions());
376 if (!maybeSupportedExtensions.has_value()) {
377 const auto& [message, code] = maybeSupportedExtensions.error();
378 LOG(ERROR) << "adapter::Device::getSupportedExtensions failed with " << code << ": "
379 << message;
380 cb(V1_2::utils::convert(code).value(), {});
381 } else {
382 cb(V1_0::ErrorStatus::NONE, maybeSupportedExtensions.value());
383 }
384 return Void();
385 }
386
getSupportedOperations(const V1_0::Model & model,getSupportedOperations_cb cb)387 Return<void> Device::getSupportedOperations(const V1_0::Model& model,
388 getSupportedOperations_cb cb) {
389 const auto result = adapter::getSupportedOperations(kDevice, model);
390 if (!result.has_value()) {
391 const auto& [message, code] = result.error();
392 LOG(ERROR) << "adapter::Device::getSupportedOperations_1_0 failed with " << code << ": "
393 << message;
394 cb(V1_0::utils::convert(code).value(), {});
395 } else {
396 cb(V1_0::ErrorStatus::NONE, result.value());
397 }
398 return Void();
399 }
400
getSupportedOperations_1_1(const V1_1::Model & model,getSupportedOperations_1_1_cb cb)401 Return<void> Device::getSupportedOperations_1_1(const V1_1::Model& model,
402 getSupportedOperations_1_1_cb cb) {
403 const auto result = adapter::getSupportedOperations(kDevice, model);
404 if (!result.has_value()) {
405 const auto& [message, code] = result.error();
406 LOG(ERROR) << "adapter::Device::getSupportedOperations_1_1 failed with " << code << ": "
407 << message;
408 cb(V1_1::utils::convert(code).value(), {});
409 } else {
410 cb(V1_0::ErrorStatus::NONE, result.value());
411 }
412 return Void();
413 }
414
getSupportedOperations_1_2(const V1_2::Model & model,getSupportedOperations_1_2_cb cb)415 Return<void> Device::getSupportedOperations_1_2(const V1_2::Model& model,
416 getSupportedOperations_1_2_cb cb) {
417 const auto result = adapter::getSupportedOperations(kDevice, model);
418 if (!result.has_value()) {
419 const auto& [message, code] = result.error();
420 LOG(ERROR) << "adapter::Device::getSupportedOperations_1_2 failed with " << code << ": "
421 << message;
422 cb(V1_2::utils::convert(code).value(), {});
423 } else {
424 cb(V1_0::ErrorStatus::NONE, result.value());
425 }
426 return Void();
427 }
428
getSupportedOperations_1_3(const V1_3::Model & model,getSupportedOperations_1_3_cb cb)429 Return<void> Device::getSupportedOperations_1_3(const V1_3::Model& model,
430 getSupportedOperations_1_3_cb cb) {
431 const auto result = adapter::getSupportedOperations(kDevice, model);
432 if (!result.has_value()) {
433 const auto& [message, code] = result.error();
434 LOG(ERROR) << "adapter::Device::getSupportedOperations_1_3 failed with " << code << ": "
435 << message;
436 cb(V1_3::utils::convert(code).value(), {});
437 } else {
438 cb(V1_3::ErrorStatus::NONE, result.value());
439 }
440 return Void();
441 }
442
getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb cb)443 Return<void> Device::getNumberOfCacheFilesNeeded(getNumberOfCacheFilesNeeded_cb cb) {
444 const auto [numModelCache, numDataCache] = kDevice->getNumberOfCacheFilesNeeded();
445 cb(V1_0::ErrorStatus::NONE, numModelCache, numDataCache);
446 return Void();
447 }
448
prepareModel(const V1_0::Model & model,const sp<V1_0::IPreparedModelCallback> & callback)449 Return<V1_0::ErrorStatus> Device::prepareModel(const V1_0::Model& model,
450 const sp<V1_0::IPreparedModelCallback>& callback) {
451 auto result = adapter::prepareModel(kDevice, kExecutor, model, callback);
452 if (!result.has_value()) {
453 auto [message, code] = std::move(result).error();
454 LOG(ERROR) << "adapter::Device::prepareModel failed with " << code << ": " << message;
455 notify(callback.get(), code, nullptr);
456 return V1_0::utils::convert(code).value();
457 }
458 return V1_0::ErrorStatus::NONE;
459 }
460
prepareModel_1_1(const V1_1::Model & model,V1_1::ExecutionPreference preference,const sp<V1_0::IPreparedModelCallback> & callback)461 Return<V1_0::ErrorStatus> Device::prepareModel_1_1(
462 const V1_1::Model& model, V1_1::ExecutionPreference preference,
463 const sp<V1_0::IPreparedModelCallback>& callback) {
464 auto result = adapter::prepareModel_1_1(kDevice, kExecutor, model, preference, callback);
465 if (!result.has_value()) {
466 auto [message, code] = std::move(result).error();
467 LOG(ERROR) << "adapter::Device::prepareModel_1_1 failed with " << code << ": " << message;
468 notify(callback.get(), code, nullptr);
469 return V1_1::utils::convert(code).value();
470 }
471 return V1_0::ErrorStatus::NONE;
472 }
473
prepareModel_1_2(const V1_2::Model & model,V1_1::ExecutionPreference preference,const hidl_vec<hidl_handle> & modelCache,const hidl_vec<hidl_handle> & dataCache,const CacheToken & token,const sp<V1_2::IPreparedModelCallback> & callback)474 Return<V1_0::ErrorStatus> Device::prepareModel_1_2(
475 const V1_2::Model& model, V1_1::ExecutionPreference preference,
476 const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache,
477 const CacheToken& token, const sp<V1_2::IPreparedModelCallback>& callback) {
478 auto result = adapter::prepareModel_1_2(kDevice, kExecutor, model, preference, modelCache,
479 dataCache, token, callback);
480 if (!result.has_value()) {
481 auto [message, code] = std::move(result).error();
482 LOG(ERROR) << "adapter::Device::prepareModel_1_2 failed with " << code << ": " << message;
483 notify(callback.get(), code, nullptr);
484 return V1_2::utils::convert(code).value();
485 }
486 return V1_0::ErrorStatus::NONE;
487 }
488
prepareModel_1_3(const V1_3::Model & model,V1_1::ExecutionPreference preference,V1_3::Priority priority,const V1_3::OptionalTimePoint & deadline,const hidl_vec<hidl_handle> & modelCache,const hidl_vec<hidl_handle> & dataCache,const CacheToken & token,const sp<V1_3::IPreparedModelCallback> & callback)489 Return<V1_3::ErrorStatus> Device::prepareModel_1_3(
490 const V1_3::Model& model, V1_1::ExecutionPreference preference, V1_3::Priority priority,
491 const V1_3::OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache,
492 const hidl_vec<hidl_handle>& dataCache, const CacheToken& token,
493 const sp<V1_3::IPreparedModelCallback>& callback) {
494 auto result = adapter::prepareModel_1_3(kDevice, kExecutor, model, preference, priority,
495 deadline, modelCache, dataCache, token, callback);
496 if (!result.has_value()) {
497 auto [message, code] = std::move(result).error();
498 LOG(ERROR) << "adapter::Device::prepareModel_1_3 failed with " << code << ": " << message;
499 notify(callback.get(), code, nullptr);
500 return V1_3::utils::convert(code).value();
501 }
502 return V1_3::ErrorStatus::NONE;
503 }
504
prepareModelFromCache(const hidl_vec<hidl_handle> & modelCache,const hidl_vec<hidl_handle> & dataCache,const CacheToken & token,const sp<V1_2::IPreparedModelCallback> & callback)505 Return<V1_0::ErrorStatus> Device::prepareModelFromCache(
506 const hidl_vec<hidl_handle>& modelCache, const hidl_vec<hidl_handle>& dataCache,
507 const CacheToken& token, const sp<V1_2::IPreparedModelCallback>& callback) {
508 auto result = adapter::prepareModelFromCache(kDevice, kExecutor, modelCache, dataCache, token,
509 callback);
510 if (!result.has_value()) {
511 auto [message, code] = std::move(result).error();
512 LOG(ERROR) << "adapter::Device::prepareModelFromCache failed with " << code << ": "
513 << message;
514 notify(callback.get(), code, nullptr);
515 return V1_2::utils::convert(code).value();
516 }
517 return V1_0::ErrorStatus::NONE;
518 }
519
prepareModelFromCache_1_3(const V1_3::OptionalTimePoint & deadline,const hidl_vec<hidl_handle> & modelCache,const hidl_vec<hidl_handle> & dataCache,const CacheToken & token,const sp<V1_3::IPreparedModelCallback> & callback)520 Return<V1_3::ErrorStatus> Device::prepareModelFromCache_1_3(
521 const V1_3::OptionalTimePoint& deadline, const hidl_vec<hidl_handle>& modelCache,
522 const hidl_vec<hidl_handle>& dataCache, const CacheToken& token,
523 const sp<V1_3::IPreparedModelCallback>& callback) {
524 auto result = adapter::prepareModelFromCache_1_3(kDevice, kExecutor, deadline, modelCache,
525 dataCache, token, callback);
526 if (!result.has_value()) {
527 auto [message, code] = std::move(result).error();
528 LOG(ERROR) << "adapter::Device::prepareModelFromCache_1_3 failed with " << code << ": "
529 << message;
530 notify(callback.get(), code, nullptr);
531 return V1_3::utils::convert(code).value();
532 }
533 return V1_3::ErrorStatus::NONE;
534 }
535
getStatus()536 Return<V1_0::DeviceStatus> Device::getStatus() {
537 return V1_0::DeviceStatus::AVAILABLE;
538 }
539
allocate(const V1_3::BufferDesc & desc,const hidl_vec<sp<V1_3::IPreparedModel>> & preparedModels,const hidl_vec<V1_3::BufferRole> & inputRoles,const hidl_vec<V1_3::BufferRole> & outputRoles,allocate_cb cb)540 Return<void> Device::allocate(const V1_3::BufferDesc& desc,
541 const hidl_vec<sp<V1_3::IPreparedModel>>& preparedModels,
542 const hidl_vec<V1_3::BufferRole>& inputRoles,
543 const hidl_vec<V1_3::BufferRole>& outputRoles, allocate_cb cb) {
544 auto result = adapter::allocate(kDevice, desc, preparedModels, inputRoles, outputRoles);
545 if (!result.has_value()) {
546 const auto [message, code] = std::move(result).error();
547 LOG(ERROR) << "adapter::Device::allocate failed with " << code << ": " << message;
548 cb(V1_3::utils::convert(code).value(), nullptr, /*token=*/0);
549 return Void();
550 }
551 auto [buffer, token] = std::move(result).value();
552 cb(V1_3::ErrorStatus::NONE, buffer, token);
553 return Void();
554 }
555
556 } // namespace android::hardware::neuralnetworks::adapter
557