1 /*
2  * Copyright (C) 2021 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 "NeuralNetworksShim"
18 
19 #include "NeuralNetworksShim.h"
20 
21 #include <android-base/logging.h>
22 #include <nnapi/Types.h>
23 
24 #include <limits>
25 #include <string>
26 #include <utility>
27 #include <vector>
28 
29 #include "ShimDevice.h"
30 #include "ShimDeviceManager.h"
31 
32 static_assert(offsetof(NnApiSLDriverImplFL5, base.implFeatureLevel) == 0,
33               ".base.implFeatureLevel is not at offset 0 of a NnApiSLDriverImplFL5 struct");
34 static_assert(offsetof(NnApiSLDriverImplFL6, base.implFeatureLevel) == 0,
35               ".base.implFeatureLevel is not at offset 0 of a NnApiSLDriverImplFL6 struct");
36 static_assert(offsetof(NnApiSLDriverImplFL7, base.implFeatureLevel) == 0,
37               ".base.implFeatureLevel is not at offset 0 of a NnApiSLDriverImplFL7 struct");
38 static_assert(offsetof(NnApiSLDriverImplFL8, base) == 0,
39               ".base is not at offset 0 of a NnApiSLDriverImplFL8 struct");
40 static_assert(offsetof(NnApiSLDriverImplFL8, base.base) == 0,
41               ".base.base is not at offset 0 of a NnApiSLDriverImplFL8 struct");
42 static_assert(offsetof(NnApiSLDriverImplFL8, base.base.implFeatureLevel) == 0,
43               ".base.base.implFeatureLevel is not at offset 0 of a NnApiSLDriverImplFL8 struct");
44 static_assert(offsetof(NnApiSLDriverImpl, implFeatureLevel) == 0,
45               ".implFeatureLevel is not at offset 0 of a NnApiSLDriverImpl struct");
46 
47 static_assert(sizeof(NnApiSLDriverImpl) == sizeof(int64_t), "NnApiSLDriverImpl size changed");
48 
49 // NOTE: NnApiSLDriverImplFL5 is currently aligned to 8 bytes. In prior versions of the Support
50 // Library interface, we added a "reserved_placeholder" to force alignment on 32-bit platforms. This
51 // may need to be done in the future if this struct again becomes unaligned. This would look like:
52 //  /**
53 //   * Extra pointer required to align to 8 bytes on 32bit archs.
54 //   */
55 //  void (*reserved_placeholder1)();
56 static_assert(sizeof(NnApiSLDriverImplFL5) == sizeof(int64_t) + 104 * sizeof(void*),
57               "NnApiSLDriverImplFL5 size changed");
58 static_assert(sizeof(NnApiSLDriverImplFL6) == sizeof(int64_t) + 104 * sizeof(void*),
59               "NnApiSLDriverImplFL6 size changed");
60 static_assert(sizeof(NnApiSLDriverImplFL7) == sizeof(int64_t) + 104 * sizeof(void*),
61               "NnApiSLDriverImplFL7 size changed");
62 static_assert(sizeof(NnApiSLDriverImplFL8) == sizeof(NnApiSLDriverImplFL7) + 2 * sizeof(void*),
63               "NnApiSLDriverImplFL8 size changed");
64 
65 static_assert(ANNSHIM_NO_ERROR == 0, "ANNSHIM_NO_ERROR has changed");
66 static_assert(ANNSHIM_FAILED_TO_LOAD_SL == 1, "ANNSHIM_FAILED_TO_LOAD_SL has changed");
67 static_assert(ANNSHIM_FAILED_TO_REGISTER_SERVICE == 2,
68               "ANNSHIM_FAILED_TO_REGISTER_SERVICE has changed");
69 static_assert(ANNSHIM_GENERAL_ERROR == 3, "ANNSHIM_GENERAL_ERROR has changed");
70 static_assert(ANNSHIM_INVALID_ARGUMENT == 4, "ANNSHIM_INVALID_ARGUMENT has changed");
71 
72 using android::neuralnetworks::shim::registerDevices;
73 using android::neuralnetworks::shim::RegistrationParams;
74 using android::neuralnetworks::shim::ShimDeviceInfo;
75 
ANeuralNetworksShim_registerSupportLibraryService(const ANeuralNetworksShimRegistrationParams * registrationParams)76 int ANeuralNetworksShim_registerSupportLibraryService(
77         const ANeuralNetworksShimRegistrationParams* registrationParams) {
78     if (registrationParams == nullptr) {
79         LOG(ERROR) << "Invalid arguments, registrationParams == nullptr ";
80         return ANNSHIM_INVALID_ARGUMENT;
81     }
82     const auto* params = reinterpret_cast<const RegistrationParams*>(registrationParams);
83 
84     NnApiSLDriverImpl* const nnapiImpl = params->nnapiSupportLibraryPackage;
85     const auto& deviceInfos = params->deviceInfos;
86     const uint32_t numberOfListenerThreads = params->numberOfListenerThreads;
87     const bool registerAsLazyService = params->registerAsLazyService;
88     const bool fallbackToMinimumSupportDevice = params->fallbackToMinimumSupportDevice;
89 
90     return static_cast<int>(registerDevices(nnapiImpl, deviceInfos, numberOfListenerThreads,
91                                             registerAsLazyService, fallbackToMinimumSupportDevice));
92 }
93 
ANeuralNetworksShimDeviceInfo_create(ANeuralNetworksShimDeviceInfo ** deviceInfo,const char * deviceName,const char * serviceName)94 int ANeuralNetworksShimDeviceInfo_create(ANeuralNetworksShimDeviceInfo** deviceInfo,
95                                          const char* deviceName, const char* serviceName) {
96     if (deviceInfo != nullptr) {
97         *deviceInfo = nullptr;
98     }
99 
100     if (deviceName == nullptr) {
101         LOG(ERROR) << "Invalid arguments, deviceName passed a nullptr";
102         return ANNSHIM_INVALID_ARGUMENT;
103     }
104 
105     auto result = new (std::nothrow)
106             ShimDeviceInfo{.deviceName = std::string(deviceName),
107                            .serviceName = (serviceName == nullptr || strlen(serviceName) == 0)
108                                                   ? std::string(deviceName)
109                                                   : std::string(serviceName)};
110     if (result == nullptr) {
111         return ANNSHIM_GENERAL_ERROR;
112     }
113     *deviceInfo = reinterpret_cast<ANeuralNetworksShimDeviceInfo*>(result);
114     return ANNSHIM_NO_ERROR;
115 }
116 
ANeuralNetworksShimDeviceInfo_free(ANeuralNetworksShimDeviceInfo * deviceInfo)117 void ANeuralNetworksShimDeviceInfo_free(ANeuralNetworksShimDeviceInfo* deviceInfo) {
118     delete reinterpret_cast<ShimDeviceInfo*>(deviceInfo);
119 }
120 
ANeuralNetworksShimRegistrationParams_create(NnApiSLDriverImpl * nnapiSupportLibraryPackage,ANeuralNetworksShimRegistrationParams ** outRegistrationParams)121 int ANeuralNetworksShimRegistrationParams_create(
122         NnApiSLDriverImpl* nnapiSupportLibraryPackage,
123         ANeuralNetworksShimRegistrationParams** outRegistrationParams) {
124     if (outRegistrationParams != nullptr) {
125         *outRegistrationParams = nullptr;
126     }
127 
128     if (nnapiSupportLibraryPackage == nullptr) {
129         LOG(ERROR) << "Invalid arguments, nnapiSupportLibraryPackage == nullptr ";
130         return ANNSHIM_INVALID_ARGUMENT;
131     }
132     if (outRegistrationParams == nullptr) {
133         LOG(ERROR) << "Invalid arguments, outRegistrationParams == nullptr ";
134         return ANNSHIM_INVALID_ARGUMENT;
135     }
136 
137     auto result = new (std::nothrow) RegistrationParams{
138             .nnapiSupportLibraryPackage = nnapiSupportLibraryPackage,
139             .registerAsLazyService = false,
140             .fallbackToMinimumSupportDevice = false,
141     };
142     if (result == nullptr) {
143         return ANNSHIM_GENERAL_ERROR;
144     }
145     *outRegistrationParams = reinterpret_cast<ANeuralNetworksShimRegistrationParams*>(result);
146     return ANNSHIM_NO_ERROR;
147 }
148 
ANeuralNetworksShimRegistrationParams_free(ANeuralNetworksShimRegistrationParams * registrationParams)149 void ANeuralNetworksShimRegistrationParams_free(
150         ANeuralNetworksShimRegistrationParams* registrationParams) {
151     delete reinterpret_cast<RegistrationParams*>(registrationParams);
152 }
153 
ANeuralNetworksShimRegistrationParams_addDeviceInfo(ANeuralNetworksShimRegistrationParams * registrationParams,const ANeuralNetworksShimDeviceInfo * deviceInfo)154 int ANeuralNetworksShimRegistrationParams_addDeviceInfo(
155         ANeuralNetworksShimRegistrationParams* registrationParams,
156         const ANeuralNetworksShimDeviceInfo* deviceInfo) {
157     if (registrationParams == nullptr) {
158         LOG(ERROR) << "Invalid arguments, registrationParams == nullptr";
159         return ANNSHIM_INVALID_ARGUMENT;
160     }
161     if (deviceInfo == nullptr) {
162         LOG(ERROR) << "Invalid arguments, deviceInfo == nullptr";
163         return ANNSHIM_INVALID_ARGUMENT;
164     }
165 
166     auto params = reinterpret_cast<RegistrationParams*>(registrationParams);
167     auto info = reinterpret_cast<const ShimDeviceInfo*>(deviceInfo);
168     params->deviceInfos.push_back(*info);
169     return ANNSHIM_NO_ERROR;
170 }
171 
ANeuralNetworksShimRegistrationParams_setNumberOfListenerThreads(ANeuralNetworksShimRegistrationParams * registrationParams,uint32_t numberOfListenerThreads)172 int ANeuralNetworksShimRegistrationParams_setNumberOfListenerThreads(
173         ANeuralNetworksShimRegistrationParams* registrationParams,
174         uint32_t numberOfListenerThreads) {
175     if (registrationParams == nullptr) {
176         LOG(ERROR) << "Invalid arguments, registrationParams == nullptr";
177         return ANNSHIM_INVALID_ARGUMENT;
178     }
179     if (registrationParams == 0) {
180         LOG(ERROR) << "Invalid arguments, numberOfListenerThreads == 0";
181         return ANNSHIM_INVALID_ARGUMENT;
182     }
183     auto params = reinterpret_cast<RegistrationParams*>(registrationParams);
184     params->numberOfListenerThreads = numberOfListenerThreads;
185     return ANNSHIM_NO_ERROR;
186 }
187 
ANeuralNetworksShimRegistrationParams_registerAsLazyService(ANeuralNetworksShimRegistrationParams * registrationParams,bool asLazy)188 int ANeuralNetworksShimRegistrationParams_registerAsLazyService(
189         ANeuralNetworksShimRegistrationParams* registrationParams, bool asLazy) {
190     if (registrationParams == nullptr) {
191         LOG(ERROR) << "Invalid arguments, registrationParams == nullptr";
192         return ANNSHIM_INVALID_ARGUMENT;
193     }
194     auto params = reinterpret_cast<RegistrationParams*>(registrationParams);
195     params->registerAsLazyService = asLazy;
196     return ANNSHIM_NO_ERROR;
197 }
198 
ANeuralNetworksShimRegistrationParams_fallbackToMinimumSupportDevice(ANeuralNetworksShimRegistrationParams * registrationParams,bool fallback)199 int ANeuralNetworksShimRegistrationParams_fallbackToMinimumSupportDevice(
200         ANeuralNetworksShimRegistrationParams* registrationParams, bool fallback) {
201     if (registrationParams == nullptr) {
202         LOG(ERROR) << "Invalid arguments, registrationParams == nullptr";
203         return ANNSHIM_INVALID_ARGUMENT;
204     }
205     auto params = reinterpret_cast<RegistrationParams*>(registrationParams);
206     params->fallbackToMinimumSupportDevice = fallback;
207     return ANNSHIM_NO_ERROR;
208 }
209