1/*
2 * Copyright (C) 2017 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#define LOG_TAG "Manager"
18
19#include "Manager.h"
20#include "HalInterfaces.h"
21#include "Utils.h"
22
23#include <android/hidl/manager/1.0/IServiceManager.h>
24#include <hidl/HidlTransportSupport.h>
25#include <hidl/ServiceManagement.h>
26
27#include <algorithm>
28#include <functional>
29
30namespace android {
31namespace nn {
32
33Device::Device(std::string name, const sp<V1_0::IDevice>& device) :
34      mName(std::move(name)), mInterface(device) {}
35
36// TODO: handle errors from initialize correctly
37bool Device::initialize() {
38#ifdef NN_DEBUGGABLE
39    static const char samplePrefix[] = "sample";
40
41    mSupported =
42            (mName.substr(0, sizeof(samplePrefix) - 1)  == samplePrefix)
43            ? getProp("debug.nn.sample.supported") : 0;
44#endif  // NN_DEBUGGABLE
45
46    ErrorStatus status = ErrorStatus::GENERAL_FAILURE;
47    Capabilities capabilities;
48    std::tie(status, capabilities) = mInterface.getCapabilities();
49
50    if (status != ErrorStatus::NONE) {
51        LOG(ERROR) << "IDevice::getCapabilities returned the error " << toString(status);
52    } else {
53        VLOG(MANAGER) << "Capab " << capabilities.float32Performance.execTime;
54        VLOG(MANAGER) << "Capab " << capabilities.quantized8Performance.execTime;
55        VLOG(MANAGER) << "Capab " << capabilities.relaxedFloat32toFloat16Performance.execTime;
56        mFloat32Performance = capabilities.float32Performance;
57        mQuantized8Performance = capabilities.quantized8Performance;
58        mRelaxedFloat32toFloat16Performance = capabilities.relaxedFloat32toFloat16Performance;
59    }
60
61    return status == ErrorStatus::NONE;
62}
63
64void Device::getSupportedOperations(const Model& hidlModel,
65                                    hidl_vec<bool>* outSupportedOperations) {
66    // Query the driver for what it can do.
67    ErrorStatus status = ErrorStatus::GENERAL_FAILURE;
68    hidl_vec<bool> supportedOperations;
69    std::tie(status, supportedOperations) = mInterface.getSupportedOperations(hidlModel);
70
71    if (status != ErrorStatus::NONE) {
72        LOG(ERROR) << "IDevice::getSupportedOperations returned the error " << toString(status);
73        // Set the supported operation vectors to all false, so we won't use this driver.
74        outSupportedOperations->resize(hidlModel.operations.size());
75        std::fill(outSupportedOperations->begin(), outSupportedOperations->end(), false);
76        return;
77    }
78    if (supportedOperations.size() != hidlModel.operations.size()) {
79        LOG(ERROR) << "IDevice::getSupportedOperations returned a vector of length "
80                   << supportedOperations.size() << " when expecting "
81                   << hidlModel.operations.size();
82        // Set the supported operation vectors to all false, so we won't use this driver.
83        outSupportedOperations->resize(hidlModel.operations.size());
84        std::fill(outSupportedOperations->begin(), outSupportedOperations->end(), false);
85        return;
86    }
87
88    *outSupportedOperations = supportedOperations;
89
90#ifdef NN_DEBUGGABLE
91    if (mSupported != 1) {
92        return;
93    }
94
95    const uint32_t baseAccumulator = std::hash<std::string>{}(mName);
96    for (size_t operationIndex = 0; operationIndex < outSupportedOperations->size();
97         operationIndex++) {
98        if (!(*outSupportedOperations)[operationIndex]) {
99            continue;
100        }
101
102        uint32_t accumulator = baseAccumulator;
103        const Operation &operation = hidlModel.operations[operationIndex];
104        accumulator ^= static_cast<uint32_t>(operation.type);
105        auto accumulateOperands = [&hidlModel, &accumulator](const hidl_vec<uint32_t>& operands) {
106            for (uint32_t operandIndex : operands) {
107                const Operand& operand = hidlModel.operands[operandIndex];
108                accumulator ^= static_cast<uint32_t>(operand.type);
109                accumulator ^= operand.dimensions.size();
110                for (uint32_t dimension : operand.dimensions) {
111                    accumulator ^= dimension;
112                    if (operand.lifetime == OperandLifeTime::CONSTANT_COPY ||
113                        operand.lifetime == OperandLifeTime::CONSTANT_REFERENCE) {
114                        accumulator ^= 1;
115                    }
116                }
117            }
118        };
119        accumulateOperands(operation.inputs);
120        accumulateOperands(operation.outputs);
121        if (accumulator & 1) {
122            (*outSupportedOperations)[operationIndex] = false;
123        }
124    }
125#endif  // NN_DEBUGGABLE
126}
127
128DeviceManager* DeviceManager::get() {
129    static DeviceManager manager;
130    return &manager;
131}
132
133void DeviceManager::findAvailableDevices() {
134    using ::android::hidl::manager::V1_0::IServiceManager;
135    VLOG(MANAGER) << "findAvailableDevices";
136
137    sp<IServiceManager> manager = hardware::defaultServiceManager();
138    if (manager == nullptr) {
139        LOG(ERROR) << "Unable to open defaultServiceManager";
140        return;
141    }
142
143    manager->listByInterface(V1_0::IDevice::descriptor, [this](const hidl_vec<hidl_string>& names) {
144        for (const auto& name : names) {
145            VLOG(MANAGER) << "Found interface " << name.c_str();
146            sp<V1_0::IDevice> device = V1_0::IDevice::getService(name);
147            if (device == nullptr) {
148                LOG(ERROR) << "Got a null IDEVICE for " << name.c_str();
149                continue;
150            }
151            registerDevice(name.c_str(), device);
152        }
153    });
154}
155
156void DeviceManager::registerDevice(const char* name, const sp<V1_0::IDevice>& device) {
157    auto d = std::make_shared<Device>(name, device);
158    if (d->initialize()) {
159        mDevices.push_back(d);
160    }
161}
162
163DeviceManager::DeviceManager() {
164    VLOG(MANAGER) << "DeviceManager::DeviceManager";
165    findAvailableDevices();
166#ifdef NN_DEBUGGABLE
167    mPartitioning = getProp("debug.nn.partition", kPartitioningDefault);
168    mDebugNNCpuOnly = (getProp("debug.nn.cpuonly") != 0);
169#endif  // NN_DEBUGGABLE
170}
171
172}  // namespace nn
173}  // namespace android
174