1 /* 2 * Copyright (C) 2018 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 "VersionedInterfaces.h" 18 19 #include "Callbacks.h" 20 #include "ExecutionBurstController.h" 21 #include "Tracing.h" 22 #include "Utils.h" 23 24 #include <android-base/logging.h> 25 #include <android-base/scopeguard.h> 26 #include <android-base/thread_annotations.h> 27 #include <functional> 28 #include <type_traits> 29 30 namespace android { 31 namespace nn { 32 33 // anonymous namespace 34 namespace { 35 36 using HidlToken = hidl_array<uint8_t, static_cast<uint32_t>(Constant::BYTE_SIZE_OF_CACHE_TOKEN)>; 37 38 const Timing kBadTiming = {.timeOnDevice = UINT64_MAX, .timeInDriver = UINT64_MAX}; 39 40 void sendFailureMessage(const sp<IPreparedModelCallback>& cb) { 41 cb->notify(ErrorStatus::GENERAL_FAILURE, nullptr); 42 } 43 44 void sendFailureMessage(const sp<PreparedModelCallback>& cb) { 45 sendFailureMessage(static_cast<sp<IPreparedModelCallback>>(cb)); 46 } 47 48 void sendFailureMessage(const sp<IExecutionCallback>& cb) { 49 cb->notify(ErrorStatus::GENERAL_FAILURE); 50 } 51 52 void sendFailureMessage(const sp<ExecutionCallback>& cb) { 53 sendFailureMessage(static_cast<sp<IExecutionCallback>>(cb)); 54 } 55 56 // This class is thread safe 57 template <typename ICallback> 58 class DeathHandler : public hardware::hidl_death_recipient { 59 public: 60 void serviceDied(uint64_t /*cookie*/, const wp<hidl::base::V1_0::IBase>& /*who*/) override { 61 LOG(ERROR) << "DeathHandler::serviceDied -- service unexpectedly died!"; 62 std::lock_guard<std::mutex> hold(mMutex); 63 std::for_each(mCallbacks.begin(), mCallbacks.end(), 64 [](const auto& cb) { sendFailureMessage(cb); }); 65 } 66 67 [[nodiscard]] base::ScopeGuard<std::function<void()>> protectCallback( 68 const sp<ICallback>& callback) { 69 registerCallback(callback); 70 return ::android::base::make_scope_guard( 71 [this, callback] { unregisterCallback(callback); }); 72 } 73 74 private : void registerCallback(const sp<ICallback>& callback) { 75 std::lock_guard<std::mutex> hold(mMutex); 76 mCallbacks.push_back(callback); 77 } 78 79 void unregisterCallback(const sp<ICallback>& callback) { 80 std::lock_guard<std::mutex> hold(mMutex); 81 mCallbacks.erase(std::remove(mCallbacks.begin(), mCallbacks.end(), callback), 82 mCallbacks.end()); 83 } 84 85 std::mutex mMutex; 86 std::vector<sp<ICallback>> mCallbacks GUARDED_BY(mMutex); 87 }; 88 89 } // anonymous namespace 90 91 class IDeviceDeathHandler : public DeathHandler<IPreparedModelCallback> {}; 92 class IPreparedModelDeathHandler : public DeathHandler<IExecutionCallback> {}; 93 94 static std::shared_ptr<VersionedIPreparedModel> makeVersionedIPreparedModel( 95 sp<V1_0::IPreparedModel> preparedModel) { 96 // verify input 97 if (!preparedModel) { 98 LOG(ERROR) << "makeVersionedIPreparedModel -- passed invalid preparedModel object."; 99 return nullptr; 100 } 101 102 // create death handler object 103 sp<IPreparedModelDeathHandler> deathHandler = new (std::nothrow) IPreparedModelDeathHandler(); 104 if (!deathHandler) { 105 LOG(ERROR) << "makeVersionedIPreparedModel -- Failed to create IPreparedModelDeathHandler."; 106 return nullptr; 107 } 108 109 // linkToDeath registers a callback that will be invoked on service death to 110 // proactively handle service crashes. If the linkToDeath call fails, 111 // asynchronous calls are susceptible to hangs if the service crashes before 112 // providing the response. 113 const Return<bool> ret = preparedModel->linkToDeath(deathHandler, 0); 114 if (!ret.isOk() || ret != true) { 115 LOG(ERROR) << "makeVersionedIPreparedModel -- Failed to register a death recipient for the " 116 "IPreparedModel object."; 117 return nullptr; 118 } 119 120 // return a valid VersionedIPreparedModel object 121 return std::make_shared<VersionedIPreparedModel>(std::move(preparedModel), 122 std::move(deathHandler)); 123 } 124 125 VersionedIPreparedModel::VersionedIPreparedModel(sp<V1_0::IPreparedModel> preparedModel, 126 sp<IPreparedModelDeathHandler> deathHandler) 127 : mPreparedModelV1_0(std::move(preparedModel)), 128 mPreparedModelV1_2(V1_2::IPreparedModel::castFrom(mPreparedModelV1_0).withDefault(nullptr)), 129 mDeathHandler(std::move(deathHandler)) {} 130 131 VersionedIPreparedModel::~VersionedIPreparedModel() { 132 // It is safe to ignore any errors resulting from this unlinkToDeath call 133 // because the VersionedIPreparedModel object is already being destroyed and 134 // its underlying IPreparedModel object is no longer being used by the NN 135 // runtime. 136 mPreparedModelV1_0->unlinkToDeath(mDeathHandler).isOk(); 137 } 138 139 ErrorStatus VersionedIPreparedModel::execute(const Request& request, MeasureTiming measure, 140 const sp<ExecutionCallback>& callback) { 141 const auto scoped = mDeathHandler->protectCallback(callback); 142 143 if (mPreparedModelV1_2 != nullptr) { 144 Return<ErrorStatus> ret = mPreparedModelV1_2->execute_1_2(request, measure, callback); 145 if (!ret.isOk()) { 146 sendFailureMessage(callback); 147 LOG(ERROR) << "execute_1_2 failure: " << ret.description(); 148 return ErrorStatus::GENERAL_FAILURE; 149 } 150 if (ret != ErrorStatus::NONE) { 151 sendFailureMessage(callback); 152 LOG(ERROR) << "execute_1_2 returned " << toString(static_cast<ErrorStatus>(ret)); 153 return static_cast<ErrorStatus>(ret); 154 } 155 callback->wait(); 156 return static_cast<ErrorStatus>(ret); 157 } else if (mPreparedModelV1_0 != nullptr) { 158 Return<ErrorStatus> ret = mPreparedModelV1_0->execute(request, callback); 159 if (!ret.isOk()) { 160 sendFailureMessage(callback); 161 LOG(ERROR) << "execute failure: " << ret.description(); 162 return ErrorStatus::GENERAL_FAILURE; 163 } 164 if (ret != ErrorStatus::NONE) { 165 sendFailureMessage(callback); 166 LOG(ERROR) << "execute returned " << toString(static_cast<ErrorStatus>(ret)); 167 return static_cast<ErrorStatus>(ret); 168 } 169 callback->wait(); 170 return static_cast<ErrorStatus>(ret); 171 } else { 172 sendFailureMessage(callback); 173 LOG(ERROR) << "execute called with no preparedModel"; 174 return ErrorStatus::GENERAL_FAILURE; 175 } 176 } 177 178 std::tuple<ErrorStatus, hidl_vec<OutputShape>, Timing> 179 VersionedIPreparedModel::executeSynchronously(const Request& request, MeasureTiming measure) { 180 const std::tuple<ErrorStatus, hidl_vec<OutputShape>, Timing> kFailure = { 181 ErrorStatus::GENERAL_FAILURE, {}, kBadTiming}; 182 183 if (mPreparedModelV1_2 != nullptr) { 184 std::tuple<ErrorStatus, hidl_vec<OutputShape>, Timing> result; 185 Return<void> ret = mPreparedModelV1_2->executeSynchronously( 186 request, measure, 187 [&result](ErrorStatus error, const hidl_vec<OutputShape>& outputShapes, 188 const Timing& timing) { 189 result = std::make_tuple(error, outputShapes, timing); 190 }); 191 if (!ret.isOk()) { 192 LOG(ERROR) << "executeSynchronously failure: " << ret.description(); 193 return kFailure; 194 } 195 return result; 196 } else { 197 // Simulate synchronous execution. 198 sp<ExecutionCallback> callback = new ExecutionCallback(); 199 ErrorStatus ret = execute(request, measure, callback); 200 if (ret != ErrorStatus::NONE) { 201 return {ret, {}, kBadTiming}; 202 } 203 callback->wait(); 204 // callback->getOutputShapes() will always return an empty hidl vector. 205 // callback->getTiming() will always return values indicating no measurement. 206 return {callback->getStatus(), callback->getOutputShapes(), callback->getTiming()}; 207 } 208 } 209 210 std::shared_ptr<ExecutionBurstController> VersionedIPreparedModel::configureExecutionBurst( 211 bool blocking) const { 212 if (mPreparedModelV1_2 != nullptr) { 213 return ExecutionBurstController::create(mPreparedModelV1_2, blocking); 214 } else { 215 return nullptr; 216 } 217 } 218 219 bool VersionedIPreparedModel::operator==(nullptr_t) const { 220 return mPreparedModelV1_0 == nullptr; 221 } 222 223 bool VersionedIPreparedModel::operator!=(nullptr_t) const { 224 return mPreparedModelV1_0 != nullptr; 225 } 226 227 std::shared_ptr<VersionedIDevice> VersionedIDevice::create(std::string serviceName, 228 sp<V1_0::IDevice> device) { 229 auto core = Core::create(std::move(device)); 230 if (!core.has_value()) { 231 LOG(ERROR) << "VersionedIDevice::create -- Failed to create Core."; 232 return nullptr; 233 } 234 235 // return a valid VersionedIDevice object 236 return std::make_shared<VersionedIDevice>(std::move(serviceName), std::move(core.value())); 237 } 238 239 VersionedIDevice::VersionedIDevice(std::string serviceName, Core core) 240 : mServiceName(std::move(serviceName)), mCore(std::move(core)) {} 241 242 std::optional<VersionedIDevice::Core> VersionedIDevice::Core::create(sp<V1_0::IDevice> device) { 243 // verify input 244 if (!device) { 245 LOG(ERROR) << "VersionedIDevice::Core::create -- passed invalid device object."; 246 return {}; 247 } 248 249 // create death handler object 250 sp<IDeviceDeathHandler> deathHandler = new (std::nothrow) IDeviceDeathHandler(); 251 if (!deathHandler) { 252 LOG(ERROR) << "VersionedIDevice::Core::create -- Failed to create IDeviceDeathHandler."; 253 return {}; 254 } 255 256 // linkToDeath registers a callback that will be invoked on service death to 257 // proactively handle service crashes. If the linkToDeath call fails, 258 // asynchronous calls are susceptible to hangs if the service crashes before 259 // providing the response. 260 const Return<bool> ret = device->linkToDeath(deathHandler, 0); 261 if (!ret.isOk() || ret != true) { 262 LOG(ERROR) 263 << "VersionedIDevice::Core::create -- Failed to register a death recipient for the " 264 "IDevice object."; 265 return {}; 266 } 267 268 // return a valid Core object 269 return Core(std::move(device), std::move(deathHandler)); 270 } 271 272 // HIDL guarantees all V1_1 interfaces inherit from their corresponding V1_0 interfaces. 273 VersionedIDevice::Core::Core(sp<V1_0::IDevice> device, sp<IDeviceDeathHandler> deathHandler) 274 : mDeviceV1_0(std::move(device)), 275 mDeviceV1_1(V1_1::IDevice::castFrom(mDeviceV1_0).withDefault(nullptr)), 276 mDeviceV1_2(V1_2::IDevice::castFrom(mDeviceV1_0).withDefault(nullptr)), 277 mDeathHandler(std::move(deathHandler)) {} 278 279 VersionedIDevice::Core::~Core() { 280 if (mDeathHandler != nullptr) { 281 CHECK(mDeviceV1_0 != nullptr); 282 // It is safe to ignore any errors resulting from this unlinkToDeath call 283 // because the VersionedIDevice::Core object is already being destroyed and 284 // its underlying IDevice object is no longer being used by the NN runtime. 285 mDeviceV1_0->unlinkToDeath(mDeathHandler).isOk(); 286 } 287 } 288 289 VersionedIDevice::Core::Core(Core&& other) noexcept 290 : mDeviceV1_0(std::move(other.mDeviceV1_0)), 291 mDeviceV1_1(std::move(other.mDeviceV1_1)), 292 mDeviceV1_2(std::move(other.mDeviceV1_2)), 293 mDeathHandler(std::move(other.mDeathHandler)) { 294 other.mDeathHandler = nullptr; 295 } 296 297 VersionedIDevice::Core& VersionedIDevice::Core::operator=(Core&& other) noexcept { 298 if (this != &other) { 299 mDeviceV1_0 = std::move(other.mDeviceV1_0); 300 mDeviceV1_1 = std::move(other.mDeviceV1_1); 301 mDeviceV1_2 = std::move(other.mDeviceV1_2); 302 mDeathHandler = std::move(other.mDeathHandler); 303 other.mDeathHandler = nullptr; 304 } 305 return *this; 306 } 307 308 template <typename T_IDevice> 309 std::pair<sp<T_IDevice>, sp<IDeviceDeathHandler>> VersionedIDevice::Core::getDeviceAndDeathHandler() 310 const { 311 return {getDevice<T_IDevice>(), mDeathHandler}; 312 } 313 314 template <typename T_IDevice, typename T_Callback> 315 Return<ErrorStatus> callProtected( 316 const char* context, const std::function<Return<ErrorStatus>(const sp<T_IDevice>&)>& fn, 317 const sp<T_IDevice>& device, const sp<T_Callback>& callback, 318 const sp<IDeviceDeathHandler>& deathHandler) { 319 const auto scoped = deathHandler->protectCallback(callback); 320 Return<ErrorStatus> ret = fn(device); 321 // Suppose there was a transport error. We have the following cases: 322 // 1. Either not due to a dead device, or due to a device that was 323 // already dead at the time of the call to protectCallback(). In 324 // this case, the callback was never signalled. 325 // 2. Due to a device that died after the call to protectCallback() but 326 // before fn() completed. In this case, the callback was (or will 327 // be) signalled by the deathHandler. 328 // Furthermore, what if there was no transport error, but the ErrorStatus is 329 // other than NONE? We'll conservatively signal the callback anyway, just in 330 // case the driver was sloppy and failed to do so. 331 if (!ret.isOk() || ret != ErrorStatus::NONE) { 332 // What if the deathHandler has signalled or will signal the callback? 333 // This is fine -- we're permitted to signal multiple times; and we're 334 // sending the same signal that the deathHandler does. 335 // 336 // What if the driver signalled the callback? Then this signal is 337 // ignored. 338 339 if (ret.isOk()) { 340 LOG(ERROR) << context << " returned " << toString(static_cast<ErrorStatus>(ret)); 341 } else { 342 LOG(ERROR) << context << " failure: " << ret.description(); 343 } 344 sendFailureMessage(callback); 345 } 346 callback->wait(); 347 return ret; 348 } 349 template <typename T_Return, typename T_IDevice> 350 Return<T_Return> callProtected(const char*, 351 const std::function<Return<T_Return>(const sp<T_IDevice>&)>& fn, 352 const sp<T_IDevice>& device, const std::nullptr_t&, 353 const sp<IDeviceDeathHandler>&) { 354 return fn(device); 355 } 356 357 template <typename T_Return, typename T_IDevice, typename T_Callback> 358 Return<T_Return> VersionedIDevice::recoverable( 359 const char* context, const std::function<Return<T_Return>(const sp<T_IDevice>&)>& fn, 360 const T_Callback& callback) const EXCLUDES(mMutex) { 361 CHECK_EQ(callback == nullptr, (std::is_same_v<T_Callback, std::nullptr_t>)); 362 363 sp<T_IDevice> device; 364 sp<IDeviceDeathHandler> deathHandler; 365 std::tie(device, deathHandler) = getDeviceAndDeathHandler<T_IDevice>(); 366 367 Return<T_Return> ret = callProtected(context, fn, device, callback, deathHandler); 368 369 if (ret.isDeadObject()) { 370 { 371 std::unique_lock lock(mMutex); 372 // It's possible that another device has already done the recovery. 373 // It's harmless but wasteful for us to do so in this case. 374 auto pingReturn = mCore.getDevice<T_IDevice>()->ping(); 375 if (pingReturn.isDeadObject()) { 376 VLOG(DRIVER) << "VersionedIDevice::recoverable(" << context << ") -- Recovering " 377 << mServiceName; 378 sp<V1_0::IDevice> recoveredDevice = V1_0::IDevice::tryGetService(mServiceName); 379 if (recoveredDevice == nullptr) { 380 VLOG(DRIVER) << "VersionedIDevice::recoverable got a null IDEVICE for " 381 << mServiceName; 382 return ret; 383 } 384 385 auto core = Core::create(std::move(recoveredDevice)); 386 if (!core.has_value()) { 387 LOG(ERROR) << "VersionedIDevice::recoverable -- Failed to create Core."; 388 return ret; 389 } 390 391 mCore = std::move(core.value()); 392 } else { 393 VLOG(DRIVER) << "VersionedIDevice::recoverable(" << context 394 << ") -- Someone else recovered " << mServiceName; 395 // Might still have a transport error, which we need to check 396 // before pingReturn goes out of scope. 397 (void)pingReturn.isOk(); 398 } 399 std::tie(device, deathHandler) = mCore.getDeviceAndDeathHandler<T_IDevice>(); 400 } 401 ret = callProtected(context, fn, device, callback, deathHandler); 402 // It's possible that the device died again, but we're only going to 403 // attempt recovery once per call to recoverable(). 404 } 405 return ret; 406 } 407 408 std::pair<ErrorStatus, Capabilities> VersionedIDevice::getCapabilities() { 409 const std::pair<ErrorStatus, Capabilities> kFailure = {ErrorStatus::GENERAL_FAILURE, {}}; 410 std::pair<ErrorStatus, Capabilities> result; 411 412 if (getDevice<V1_2::IDevice>() != nullptr) { 413 NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_INITIALIZATION, "getCapabilities_1_2"); 414 Return<void> ret = recoverable<void, V1_2::IDevice>( 415 __FUNCTION__, [&result](const sp<V1_2::IDevice>& device) { 416 return device->getCapabilities_1_2( 417 [&result](ErrorStatus error, const Capabilities& capabilities) { 418 result = std::make_pair(error, capabilities); 419 }); 420 }); 421 if (!ret.isOk()) { 422 LOG(ERROR) << "getCapabilities_1_2 failure: " << ret.description(); 423 return {ErrorStatus::GENERAL_FAILURE, {}}; 424 } 425 } else if (getDevice<V1_1::IDevice>() != nullptr) { 426 NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_INITIALIZATION, "getCapabilities_1_1"); 427 Return<void> ret = recoverable<void, V1_1::IDevice>( 428 __FUNCTION__, [&result](const sp<V1_1::IDevice>& device) { 429 return device->getCapabilities_1_1( 430 [&result](ErrorStatus error, const V1_1::Capabilities& capabilities) { 431 // Time taken to convert capabilities is trivial 432 result = std::make_pair(error, convertToV1_2(capabilities)); 433 }); 434 }); 435 if (!ret.isOk()) { 436 LOG(ERROR) << "getCapabilities_1_1 failure: " << ret.description(); 437 return kFailure; 438 } 439 } else if (getDevice<V1_0::IDevice>() != nullptr) { 440 NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_INITIALIZATION, "getCapabilities"); 441 Return<void> ret = recoverable<void, V1_0::IDevice>( 442 __FUNCTION__, [&result](const sp<V1_0::IDevice>& device) { 443 return device->getCapabilities( 444 [&result](ErrorStatus error, const V1_0::Capabilities& capabilities) { 445 // Time taken to convert capabilities is trivial 446 result = std::make_pair(error, convertToV1_2(capabilities)); 447 }); 448 }); 449 if (!ret.isOk()) { 450 LOG(ERROR) << "getCapabilities failure: " << ret.description(); 451 return kFailure; 452 } 453 } else { 454 LOG(ERROR) << "Device not available!"; 455 return {ErrorStatus::DEVICE_UNAVAILABLE, {}}; 456 } 457 458 return result; 459 } 460 461 std::pair<ErrorStatus, hidl_vec<Extension>> VersionedIDevice::getSupportedExtensions() { 462 const std::pair<ErrorStatus, hidl_vec<Extension>> kFailure = {ErrorStatus::GENERAL_FAILURE, {}}; 463 NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_COMPILATION, "getSupportedExtensions"); 464 if (getDevice<V1_2::IDevice>() != nullptr) { 465 std::pair<ErrorStatus, hidl_vec<Extension>> result; 466 Return<void> ret = recoverable<void, V1_2::IDevice>( 467 __FUNCTION__, [&result](const sp<V1_2::IDevice>& device) { 468 return device->getSupportedExtensions( 469 [&result](ErrorStatus error, const hidl_vec<Extension>& extensions) { 470 result = std::make_pair(error, extensions); 471 }); 472 }); 473 if (!ret.isOk()) { 474 LOG(ERROR) << "getSupportedExtensions failure: " << ret.description(); 475 return kFailure; 476 } 477 return result; 478 } else if (getDevice<V1_0::IDevice>() != nullptr) { 479 return {ErrorStatus::NONE, {/* No extensions. */}}; 480 } else { 481 LOG(ERROR) << "Device not available!"; 482 return {ErrorStatus::DEVICE_UNAVAILABLE, {}}; 483 } 484 } 485 486 std::pair<ErrorStatus, hidl_vec<bool>> VersionedIDevice::getSupportedOperations( 487 const Model& model, IModelSlicer* slicer) { 488 const std::pair<ErrorStatus, hidl_vec<bool>> kFailure = {ErrorStatus::GENERAL_FAILURE, {}}; 489 std::pair<ErrorStatus, hidl_vec<bool>> result; 490 491 auto noneSupported = [&model] { 492 hidl_vec<bool> supported(model.operations.size()); 493 std::fill(supported.begin(), supported.end(), false); 494 return std::make_pair(ErrorStatus::NONE, std::move(supported)); 495 }; 496 497 auto remappedResult = [&model](const std::pair<ErrorStatus, hidl_vec<bool>>& result, 498 const std::function<uint32_t(uint32_t)>& 499 submodelOperationIndexToModelOperationIndex) { 500 const ErrorStatus status = result.first; 501 const hidl_vec<bool>& supported = result.second; 502 hidl_vec<bool> remappedSupported(model.operations.size()); 503 std::fill(remappedSupported.begin(), remappedSupported.end(), false); 504 for (size_t i = 0; i < supported.size(); ++i) { 505 if (supported[i]) { 506 remappedSupported[submodelOperationIndexToModelOperationIndex(i)] = true; 507 } 508 } 509 return std::make_pair(status, std::move(remappedSupported)); 510 }; 511 512 if (getDevice<V1_2::IDevice>() != nullptr) { 513 NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_COMPILATION, "getSupportedOperations_1_2"); 514 Return<void> ret = recoverable<void, V1_2::IDevice>( 515 __FUNCTION__, [&model, &result](const sp<V1_2::IDevice>& device) { 516 return device->getSupportedOperations_1_2( 517 model, [&result](ErrorStatus error, const hidl_vec<bool>& supported) { 518 result = std::make_pair(error, supported); 519 }); 520 }); 521 if (!ret.isOk()) { 522 LOG(ERROR) << "getSupportedOperations_1_2 failure: " << ret.description(); 523 return kFailure; 524 } 525 return result; 526 } 527 528 if (getDevice<V1_1::IDevice>() != nullptr) { 529 const bool compliant = compliantWithV1_1(model); 530 if (compliant || slicer) { 531 V1_1::Model model11; 532 std::function<uint32_t(uint32_t)> submodelOperationIndexToModelOperationIndex; 533 if (compliant) { 534 model11 = convertToV1_1(model); 535 } else { 536 const auto slice11 = slicer->getSliceV1_1(); 537 if (!slice11.has_value()) { 538 return noneSupported(); 539 } 540 std::tie(model11, submodelOperationIndexToModelOperationIndex) = *slice11; 541 } 542 NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_COMPILATION, 543 "getSupportedOperations_1_1"); 544 Return<void> ret = recoverable<void, V1_1::IDevice>( 545 __FUNCTION__, [&model11, &result](const sp<V1_1::IDevice>& device) { 546 return device->getSupportedOperations_1_1( 547 model11, 548 [&result](ErrorStatus error, const hidl_vec<bool>& supported) { 549 result = std::make_pair(error, supported); 550 }); 551 }); 552 if (!ret.isOk()) { 553 LOG(ERROR) << "getSupportedOperations_1_1 failure: " << ret.description(); 554 return kFailure; 555 } 556 if (!compliant) { 557 return remappedResult(result, submodelOperationIndexToModelOperationIndex); 558 } 559 } 560 return result; 561 } 562 563 if (getDevice<V1_0::IDevice>() != nullptr) { 564 const bool compliant = compliantWithV1_0(model); 565 if (compliant || slicer) { 566 V1_0::Model model10; 567 std::function<uint32_t(uint32_t)> submodelOperationIndexToModelOperationIndex; 568 if (compliant) { 569 model10 = convertToV1_0(model); 570 } else { 571 const auto slice10 = slicer->getSliceV1_0(); 572 if (!slice10.has_value()) { 573 return noneSupported(); 574 } 575 std::tie(model10, submodelOperationIndexToModelOperationIndex) = *slice10; 576 } 577 NNTRACE_FULL(NNTRACE_LAYER_IPC, NNTRACE_PHASE_COMPILATION, "getSupportedOperations"); 578 Return<void> ret = recoverable<void, V1_0::IDevice>( 579 __FUNCTION__, [&model10, &result](const sp<V1_0::IDevice>& device) { 580 return device->getSupportedOperations( 581 model10, 582 [&result](ErrorStatus error, const hidl_vec<bool>& supported) { 583 result = std::make_pair(error, supported); 584 }); 585 }); 586 if (!ret.isOk()) { 587 LOG(ERROR) << "getSupportedOperations failure: " << ret.description(); 588 return kFailure; 589 } 590 if (!compliant) { 591 return remappedResult(result, submodelOperationIndexToModelOperationIndex); 592 } 593 } 594 return result; 595 } 596 597 return kFailure; 598 } 599 600 std::pair<ErrorStatus, std::shared_ptr<VersionedIPreparedModel>> VersionedIDevice::prepareModel( 601 const Model& model, ExecutionPreference preference, const hidl_vec<hidl_handle>& modelCache, 602 const hidl_vec<hidl_handle>& dataCache, const HidlToken& token) { 603 const std::pair<ErrorStatus, std::shared_ptr<VersionedIPreparedModel>> kFailure = { 604 ErrorStatus::GENERAL_FAILURE, nullptr}; 605 606 const sp<PreparedModelCallback> callback = new (std::nothrow) PreparedModelCallback(); 607 if (callback == nullptr) { 608 LOG(ERROR) << "prepareModel failed to create callback object"; 609 return kFailure; 610 } 611 612 // If 1.2 device, try preparing model 613 if (getDevice<V1_2::IDevice>() != nullptr) { 614 const Return<ErrorStatus> ret = recoverable<ErrorStatus, V1_2::IDevice>( 615 __FUNCTION__, 616 [&model, &preference, &modelCache, &dataCache, &token, 617 &callback](const sp<V1_2::IDevice>& device) { 618 return device->prepareModel_1_2(model, preference, modelCache, dataCache, token, 619 callback); 620 }, 621 callback); 622 if (!ret.isOk()) { 623 LOG(ERROR) << "prepareModel_1_2 failure: " << ret.description(); 624 return kFailure; 625 } 626 if (ret != ErrorStatus::NONE) { 627 LOG(ERROR) << "prepareModel_1_2 returned " << toString(static_cast<ErrorStatus>(ret)); 628 return kFailure; 629 } 630 callback->wait(); 631 return {callback->getStatus(), makeVersionedIPreparedModel(callback->getPreparedModel())}; 632 } 633 634 // If 1.1 device, try preparing model (requires conversion) 635 if (getDevice<V1_1::IDevice>() != nullptr) { 636 bool compliant = false; 637 V1_1::Model model11; 638 { 639 // Attribute time spent in model inspection and conversion to 640 // Runtime, as the time may be substantial (0.03ms for mobilenet, 641 // but could be larger for other models). 642 NNTRACE_FULL_SUBTRACT(NNTRACE_LAYER_RUNTIME, NNTRACE_PHASE_COMPILATION, 643 "VersionedIDevice::prepareModel_1_1"); 644 compliant = compliantWithV1_1(model); 645 if (compliant) { 646 model11 = convertToV1_1(model); // copy is elided 647 } 648 } 649 if (compliant) { 650 const Return<ErrorStatus> ret = recoverable<ErrorStatus, V1_1::IDevice>( 651 __FUNCTION__, 652 [&model11, &preference, &callback](const sp<V1_1::IDevice>& device) { 653 return device->prepareModel_1_1(model11, preference, callback); 654 }, 655 callback); 656 if (!ret.isOk()) { 657 LOG(ERROR) << "prepareModel_1_1 failure: " << ret.description(); 658 return kFailure; 659 } 660 if (ret != ErrorStatus::NONE) { 661 LOG(ERROR) << "prepareModel_1_1 returned " 662 << toString(static_cast<ErrorStatus>(ret)); 663 return kFailure; 664 } 665 callback->wait(); 666 return {callback->getStatus(), 667 makeVersionedIPreparedModel(callback->getPreparedModel())}; 668 } 669 670 LOG(ERROR) << "Could not handle prepareModel_1_1!"; 671 return kFailure; 672 } 673 674 // If 1.0 device, try preparing model (requires conversion) 675 if (getDevice<V1_0::IDevice>() != nullptr) { 676 bool compliant = false; 677 V1_0::Model model10; 678 { 679 // Attribute time spent in model inspection and conversion to 680 // Runtime, as the time may be substantial (0.03ms for mobilenet, 681 // but could be larger for other models). 682 NNTRACE_FULL_SUBTRACT(NNTRACE_LAYER_RUNTIME, NNTRACE_PHASE_COMPILATION, 683 "VersionedIDevice::prepareModel"); 684 compliant = compliantWithV1_0(model); 685 if (compliant) { 686 model10 = convertToV1_0(model); // copy is elided 687 } 688 } 689 if (compliant) { 690 const Return<ErrorStatus> ret = recoverable<ErrorStatus, V1_0::IDevice>( 691 __FUNCTION__, 692 [&model10, &callback](const sp<V1_0::IDevice>& device) { 693 return device->prepareModel(model10, callback); 694 }, 695 callback); 696 if (!ret.isOk()) { 697 LOG(ERROR) << "prepareModel failure: " << ret.description(); 698 return kFailure; 699 } 700 if (ret != ErrorStatus::NONE) { 701 LOG(ERROR) << "prepareModel returned " << toString(static_cast<ErrorStatus>(ret)); 702 return kFailure; 703 } 704 callback->wait(); 705 return {callback->getStatus(), 706 makeVersionedIPreparedModel(callback->getPreparedModel())}; 707 } 708 709 LOG(ERROR) << "Could not handle prepareModel!"; 710 return kFailure; 711 } 712 713 // Return error because there is no valid device 714 LOG(ERROR) << "prepareModel called with no device"; 715 return kFailure; 716 } 717 718 std::pair<ErrorStatus, std::shared_ptr<VersionedIPreparedModel>> 719 VersionedIDevice::prepareModelFromCache(const hidl_vec<hidl_handle>& modelCache, 720 const hidl_vec<hidl_handle>& dataCache, 721 const HidlToken& token) { 722 const std::pair<ErrorStatus, std::shared_ptr<VersionedIPreparedModel>> kFailure = { 723 ErrorStatus::GENERAL_FAILURE, nullptr}; 724 725 const sp<PreparedModelCallback> callback = new (std::nothrow) PreparedModelCallback(); 726 if (callback == nullptr) { 727 LOG(ERROR) << "prepareModelFromCache failed to create callback object"; 728 return kFailure; 729 } 730 731 if (getDevice<V1_2::IDevice>() != nullptr) { 732 const Return<ErrorStatus> ret = recoverable<ErrorStatus, V1_2::IDevice>( 733 __FUNCTION__, 734 [&modelCache, &dataCache, &token, &callback](const sp<V1_2::IDevice>& device) { 735 return device->prepareModelFromCache(modelCache, dataCache, token, callback); 736 }, 737 callback); 738 if (!ret.isOk()) { 739 LOG(ERROR) << "prepareModelFromCache failure: " << ret.description(); 740 return kFailure; 741 } 742 if (ret != ErrorStatus::NONE) { 743 LOG(ERROR) << "prepareModelFromCache returned " 744 << toString(static_cast<ErrorStatus>(ret)); 745 return kFailure; 746 } 747 callback->wait(); 748 return {callback->getStatus(), makeVersionedIPreparedModel(callback->getPreparedModel())}; 749 } 750 751 if (getDevice<V1_1::IDevice>() != nullptr || getDevice<V1_0::IDevice>() != nullptr) { 752 LOG(ERROR) << "prepareModelFromCache called on V1_1 or V1_0 device"; 753 return kFailure; 754 } 755 756 LOG(ERROR) << "prepareModelFromCache called with no device"; 757 return kFailure; 758 } 759 760 DeviceStatus VersionedIDevice::getStatus() { 761 if (getDevice<V1_0::IDevice>() == nullptr) { 762 LOG(ERROR) << "Device not available!"; 763 return DeviceStatus::UNKNOWN; 764 } 765 766 Return<DeviceStatus> ret = recoverable<DeviceStatus, V1_0::IDevice>( 767 __FUNCTION__, [](const sp<V1_0::IDevice>& device) { return device->getStatus(); }); 768 769 if (!ret.isOk()) { 770 LOG(ERROR) << "getStatus failure: " << ret.description(); 771 return DeviceStatus::UNKNOWN; 772 } 773 return static_cast<DeviceStatus>(ret); 774 } 775 776 int64_t VersionedIDevice::getFeatureLevel() { 777 constexpr int64_t kFailure = -1; 778 779 if (getDevice<V1_2::IDevice>() != nullptr) { 780 return __ANDROID_API_Q__; 781 } else if (getDevice<V1_1::IDevice>() != nullptr) { 782 return __ANDROID_API_P__; 783 } else if (getDevice<V1_0::IDevice>() != nullptr) { 784 return __ANDROID_API_O_MR1__; 785 } else { 786 LOG(ERROR) << "Device not available!"; 787 return kFailure; 788 } 789 } 790 791 int32_t VersionedIDevice::getType() const { 792 constexpr int32_t kFailure = -1; 793 std::pair<ErrorStatus, DeviceType> result; 794 795 if (getDevice<V1_2::IDevice>() != nullptr) { 796 Return<void> ret = recoverable<void, V1_2::IDevice>( 797 __FUNCTION__, [&result](const sp<V1_2::IDevice>& device) { 798 return device->getType([&result](ErrorStatus error, DeviceType deviceType) { 799 result = std::make_pair(error, deviceType); 800 }); 801 }); 802 if (!ret.isOk()) { 803 LOG(ERROR) << "getType failure: " << ret.description(); 804 return kFailure; 805 } 806 return static_cast<int32_t>(result.second); 807 } else { 808 LOG(INFO) << "Unknown NNAPI device type."; 809 return ANEURALNETWORKS_DEVICE_UNKNOWN; 810 } 811 } 812 813 std::pair<ErrorStatus, hidl_string> VersionedIDevice::getVersionString() { 814 const std::pair<ErrorStatus, hidl_string> kFailure = {ErrorStatus::GENERAL_FAILURE, ""}; 815 std::pair<ErrorStatus, hidl_string> result; 816 817 if (getDevice<V1_2::IDevice>() != nullptr) { 818 Return<void> ret = recoverable<void, V1_2::IDevice>( 819 __FUNCTION__, [&result](const sp<V1_2::IDevice>& device) { 820 return device->getVersionString( 821 [&result](ErrorStatus error, const hidl_string& version) { 822 result = std::make_pair(error, version); 823 }); 824 }); 825 if (!ret.isOk()) { 826 LOG(ERROR) << "getVersion failure: " << ret.description(); 827 return kFailure; 828 } 829 return result; 830 } else if (getDevice<V1_1::IDevice>() != nullptr || getDevice<V1_0::IDevice>() != nullptr) { 831 return {ErrorStatus::NONE, "UNKNOWN"}; 832 } else { 833 LOG(ERROR) << "Could not handle getVersionString"; 834 return kFailure; 835 } 836 } 837 838 std::tuple<ErrorStatus, uint32_t, uint32_t> VersionedIDevice::getNumberOfCacheFilesNeeded() { 839 constexpr std::tuple<ErrorStatus, uint32_t, uint32_t> kFailure = {ErrorStatus::GENERAL_FAILURE, 840 0, 0}; 841 std::tuple<ErrorStatus, uint32_t, uint32_t> result; 842 843 if (getDevice<V1_2::IDevice>() != nullptr) { 844 Return<void> ret = recoverable<void, V1_2::IDevice>( 845 __FUNCTION__, [&result](const sp<V1_2::IDevice>& device) { 846 return device->getNumberOfCacheFilesNeeded([&result](ErrorStatus error, 847 uint32_t numModelCache, 848 uint32_t numDataCache) { 849 result = {error, numModelCache, numDataCache}; 850 }); 851 }); 852 if (!ret.isOk()) { 853 LOG(ERROR) << "getNumberOfCacheFilesNeeded failure: " << ret.description(); 854 return kFailure; 855 } 856 return result; 857 } else if (getDevice<V1_1::IDevice>() != nullptr || getDevice<V1_0::IDevice>() != nullptr) { 858 return {ErrorStatus::NONE, 0, 0}; 859 } else { 860 LOG(ERROR) << "Could not handle getNumberOfCacheFilesNeeded"; 861 return kFailure; 862 } 863 } 864 865 bool VersionedIDevice::operator==(nullptr_t) const { 866 return getDevice<V1_0::IDevice>() == nullptr; 867 } 868 869 bool VersionedIDevice::operator!=(nullptr_t) const { 870 return getDevice<V1_0::IDevice>() != nullptr; 871 } 872 873 } // namespace nn 874 } // namespace android 875