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 "VersionedIDevice.h"
18
19#include "Utils.h"
20
21#include <android-base/logging.h>
22
23namespace android {
24namespace nn {
25
26// HIDL guarantees all V1_1 interfaces inherit from their corresponding V1_0 interfaces.
27VersionedIDevice::VersionedIDevice(sp<V1_0::IDevice> device) :
28        mDeviceV1_0(device),
29        mDeviceV1_1(V1_1::IDevice::castFrom(mDeviceV1_0).withDefault(nullptr)) {}
30
31std::pair<ErrorStatus, Capabilities> VersionedIDevice::getCapabilities() {
32    std::pair<ErrorStatus, Capabilities> result;
33
34    if (mDeviceV1_1 != nullptr) {
35        Return<void> ret = mDeviceV1_1->getCapabilities_1_1(
36            [&result](ErrorStatus error, const Capabilities& capabilities) {
37                result = std::make_pair(error, capabilities);
38            });
39        if (!ret.isOk()) {
40            LOG(ERROR) << "getCapabilities_1_1 failure: " << ret.description();
41            return {ErrorStatus::GENERAL_FAILURE, {}};
42        }
43    } else if (mDeviceV1_0 != nullptr) {
44        Return<void> ret = mDeviceV1_0->getCapabilities(
45            [&result](ErrorStatus error, const V1_0::Capabilities& capabilities) {
46                result = std::make_pair(error, convertToV1_1(capabilities));
47            });
48        if (!ret.isOk()) {
49            LOG(ERROR) << "getCapabilities failure: " << ret.description();
50            return {ErrorStatus::GENERAL_FAILURE, {}};
51        }
52    } else {
53        LOG(ERROR) << "Device not available!";
54        return {ErrorStatus::DEVICE_UNAVAILABLE, {}};
55    }
56
57    return result;
58}
59
60std::pair<ErrorStatus, hidl_vec<bool>> VersionedIDevice::getSupportedOperations(
61        const Model& model) {
62    std::pair<ErrorStatus, hidl_vec<bool>> result;
63
64    if (mDeviceV1_1 != nullptr) {
65        Return<void> ret = mDeviceV1_1->getSupportedOperations_1_1(
66            model, [&result](ErrorStatus error, const hidl_vec<bool>& supported) {
67                result = std::make_pair(error, supported);
68            });
69        if (!ret.isOk()) {
70            LOG(ERROR) << "getSupportedOperations_1_1 failure: " << ret.description();
71            return {ErrorStatus::GENERAL_FAILURE, {}};
72        }
73    } else if (mDeviceV1_0 != nullptr && compliantWithV1_0(model)) {
74        Return<void> ret = mDeviceV1_0->getSupportedOperations(
75            convertToV1_0(model), [&result](ErrorStatus error, const hidl_vec<bool>& supported) {
76                result = std::make_pair(error, supported);
77            });
78        if (!ret.isOk()) {
79            LOG(ERROR) << "getSupportedOperations failure: " << ret.description();
80            return {ErrorStatus::GENERAL_FAILURE, {}};
81        }
82    } else {
83        // TODO: partition the model such that v1.1 ops are not passed to v1.0
84        // device
85        LOG(ERROR) << "Could not handle getSupportedOperations!";
86        return {ErrorStatus::GENERAL_FAILURE, {}};
87    }
88
89    return result;
90}
91
92ErrorStatus VersionedIDevice::prepareModel(const Model& model, ExecutionPreference preference,
93                                           const sp<IPreparedModelCallback>& callback) {
94    if (mDeviceV1_1 != nullptr) {
95        Return<ErrorStatus> ret = mDeviceV1_1->prepareModel_1_1(model, preference, callback);
96        if (!ret.isOk()) {
97            LOG(ERROR) << "prepareModel_1_1 failure: " << ret.description();
98            return ErrorStatus::GENERAL_FAILURE;
99        }
100        return static_cast<ErrorStatus>(ret);
101    } else if (mDeviceV1_0 != nullptr && compliantWithV1_0(model)) {
102        Return<ErrorStatus> ret = mDeviceV1_0->prepareModel(convertToV1_0(model), callback);
103        if (!ret.isOk()) {
104            LOG(ERROR) << "prepareModel failure: " << ret.description();
105            return ErrorStatus::GENERAL_FAILURE;
106        }
107        return static_cast<ErrorStatus>(ret);
108    } else {
109        // TODO: partition the model such that v1.1 ops are not passed to v1.0
110        // device
111        LOG(ERROR) << "Could not handle prepareModel!";
112        return ErrorStatus::GENERAL_FAILURE;
113    }
114}
115
116DeviceStatus VersionedIDevice::getStatus() {
117    if (mDeviceV1_0 == nullptr) {
118        LOG(ERROR) << "Device not available!";
119        return DeviceStatus::UNKNOWN;
120    }
121
122    Return<DeviceStatus> ret = mDeviceV1_0->getStatus();
123
124    if (!ret.isOk()) {
125        LOG(ERROR) << "getStatus failure: " << ret.description();
126        return DeviceStatus::UNKNOWN;
127    }
128    return static_cast<DeviceStatus>(ret);
129}
130
131bool VersionedIDevice::operator==(nullptr_t) {
132    return mDeviceV1_0 == nullptr;
133}
134
135bool VersionedIDevice::operator!=(nullptr_t) {
136    return mDeviceV1_0 != nullptr;
137}
138
139}  // namespace nn
140}  // namespace android
141