Home | History | Annotate | Download | only in runtime
      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