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 
30 namespace android {
31 namespace nn {
32 
Device(std::string name,const sp<V1_0::IDevice> & device)33 Device::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
initialize()37 bool 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 
getSupportedOperations(const Model & hidlModel,hidl_vec<bool> * outSupportedOperations)64 void 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 
get()128 DeviceManager* DeviceManager::get() {
129     static DeviceManager manager;
130     return &manager;
131 }
132 
findAvailableDevices()133 void 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 
registerDevice(const char * name,const sp<V1_0::IDevice> & device)156 void 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 
DeviceManager()163 DeviceManager::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