1 /*
2 * Copyright (C) 2019 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 "TypeManager"
18
19 #include "TypeManager.h"
20
21 #include <LegacyUtils.h>
22 #include <android-base/file.h>
23 #include <android-base/properties.h>
24
25 #include <algorithm>
26 #include <limits>
27 #include <map>
28 #include <memory>
29 #include <string>
30 #include <string_view>
31 #include <vector>
32
33 #ifndef NN_COMPATIBILITY_LIBRARY_BUILD
34 #include <PackageInfo.h>
35 #include <binder/IServiceManager.h>
36 #include <procpartition/procpartition.h>
37 #endif // NN_COMPATIBILITY_LIBRARY_BUILD
38
39 namespace android {
40 namespace nn {
41
42 // Replacement function for std::string_view::starts_with()
43 // which shall be available in C++20.
44 #if __cplusplus >= 202000L
45 #error "When upgrading to C++20, remove this error and file a bug to remove this workaround."
46 #endif
StartsWith(std::string_view sv,std::string_view prefix)47 inline bool StartsWith(std::string_view sv, std::string_view prefix) {
48 return sv.substr(0u, prefix.size()) == prefix;
49 }
50
51 namespace {
52
53 constexpr uint32_t kMaxPrefix = (1 << kExtensionPrefixBits) - 1;
54
55 // Checks if the two structures contain the same information. The order of
56 // operand types within the structures does not matter.
equal(const Extension & a,const Extension & b)57 bool equal(const Extension& a, const Extension& b) {
58 NN_RET_CHECK_EQ(a.name, b.name);
59 // Relies on the fact that TypeManager sorts operandTypes.
60 NN_RET_CHECK(a.operandTypes == b.operandTypes);
61 return true;
62 }
63
64 #ifndef NN_COMPATIBILITY_LIBRARY_BUILD
65
66 // Property for disabling NNAPI vendor extensions on product image (used on GSI /product image,
67 // which can't use NNAPI vendor extensions).
68 const char kVExtProductDeny[] = "ro.nnapi.extensions.deny_on_product";
isNNAPIVendorExtensionsUseAllowedInProductImage()69 bool isNNAPIVendorExtensionsUseAllowedInProductImage() {
70 const std::string vExtProductDeny = android::base::GetProperty(kVExtProductDeny, "");
71 return vExtProductDeny.empty();
72 }
73
74 // The file containing the list of Android apps and binaries allowed to use vendor extensions.
75 // Each line of the file contains new entry. If entry is prefixed by
76 // '/' slash, then it's a native binary path (e.g. '/data/foo'). If not, it's a name
77 // of Android app package (e.g. 'com.foo.bar').
78 const char kAppAllowlistPath[] = "/vendor/etc/nnapi_extensions_app_allowlist";
79 const char kCtsAllowlist[] = "/data/local/tmp/CTSNNAPITestCases";
getVendorExtensionAllowlistedApps()80 std::vector<std::string> getVendorExtensionAllowlistedApps() {
81 std::string data;
82 // Allowlist CTS by default.
83 std::vector<std::string> allowlist = {kCtsAllowlist};
84
85 if (!android::base::ReadFileToString(kAppAllowlistPath, &data)) {
86 // Return default allowlist (no app can use extensions).
87 LOG(INFO) << "Failed to read " << kAppAllowlistPath
88 << " ; No app allowlisted for vendor extensions use.";
89 return allowlist;
90 }
91
92 std::istringstream streamData(data);
93 std::string line;
94 while (std::getline(streamData, line)) {
95 // Do some basic validity check on entry, it's either
96 // fs path or package name.
97 if (StartsWith(line, "/") || line.find('.') != std::string::npos) {
98 allowlist.push_back(line);
99 } else {
100 LOG(ERROR) << kAppAllowlistPath << " - Invalid entry: " << line;
101 }
102 }
103 return allowlist;
104 }
105
106 // Since Android S we allow use of vendor extensions for all
107 // non-system applications without need to put the binary
108 // name on allowlist
allowVendorExtensionsForAllNonSystemClients()109 static bool allowVendorExtensionsForAllNonSystemClients() {
110 #if defined(__BIONIC__)
111 return android_get_device_api_level() >= __ANDROID_API_S__;
112 #else
113 return true;
114 #endif // __BIONIC__
115 }
116
117 #endif // NN_COMPATIBILITY_LIBRARY_BUILD
118
119 } // namespace
120
TypeManager()121 TypeManager::TypeManager() {
122 VLOG(MANAGER) << "TypeManager::TypeManager";
123 #ifndef NN_COMPATIBILITY_LIBRARY_BUILD
124 mExtensionsAllowed = TypeManager::isExtensionsUseAllowed(
125 AppInfoFetcher::get()->getAppInfo(), isNNAPIVendorExtensionsUseAllowedInProductImage(),
126 getVendorExtensionAllowlistedApps());
127 #else
128 mExtensionsAllowed = true;
129 #endif // NN_COMPATIBILITY_LIBRARY_BUILD
130 VLOG(MANAGER) << "NNAPI Vendor extensions enabled: " << mExtensionsAllowed;
131 findAvailableExtensions();
132 }
133
134 #ifndef NN_COMPATIBILITY_LIBRARY_BUILD
isExtensionsUseAllowed(const AppInfoFetcher::AppInfo & appPackageInfo,bool useOnProductImageEnabled,const std::vector<std::string> & allowlist)135 bool TypeManager::isExtensionsUseAllowed(const AppInfoFetcher::AppInfo& appPackageInfo,
136 bool useOnProductImageEnabled,
137 const std::vector<std::string>& allowlist) {
138 // Only selected partitions and user-installed apps (/data)
139 // are allowed to use extensions.
140 if (StartsWith(appPackageInfo.binaryPath, "/vendor/") ||
141 StartsWith(appPackageInfo.binaryPath, "/odm/") ||
142 StartsWith(appPackageInfo.binaryPath, "/data/") ||
143 (StartsWith(appPackageInfo.binaryPath, "/product/") && useOnProductImageEnabled)) {
144 if (allowVendorExtensionsForAllNonSystemClients()) {
145 return true;
146 }
147 #ifdef NN_DEBUGGABLE
148 // Only on userdebug and eng builds.
149 // When running tests with mma and adb push.
150 if (StartsWith(appPackageInfo.binaryPath, "/data/nativetest") ||
151 // When running tests with Atest.
152 StartsWith(appPackageInfo.binaryPath, "/data/local/tmp/NeuralNetworksTest_")) {
153 return true;
154 }
155 #endif // NN_DEBUGGABLE
156 return std::find(allowlist.begin(), allowlist.end(), appPackageInfo.binaryPath) !=
157 allowlist.end();
158 } else if (appPackageInfo.binaryPath == "/system/bin/app_process64" ||
159 appPackageInfo.binaryPath == "/system/bin/app_process32") {
160 // App is (not system app) OR (vendor app) OR (product app AND product enabled)
161 if (!appPackageInfo.appIsSystemApp || appPackageInfo.appIsOnVendorImage ||
162 (appPackageInfo.appIsOnProductImage && useOnProductImageEnabled)) {
163 if (allowVendorExtensionsForAllNonSystemClients()) {
164 // No need for allowlist
165 return true;
166 } else {
167 // Check if app is on allowlist.
168 return std::find(allowlist.begin(), allowlist.end(),
169 appPackageInfo.appPackageName) != allowlist.end();
170 }
171 }
172 }
173 return false;
174 }
175 #endif // NN_COMPATIBILITY_LIBRARY_BUILD
176
findAvailableExtensions()177 void TypeManager::findAvailableExtensions() {
178 for (const std::shared_ptr<Device>& device : mDeviceManager->getDrivers()) {
179 for (const Extension& extension : device->getSupportedExtensions()) {
180 registerExtension(extension, device->getName());
181 }
182 }
183 }
184
registerExtension(Extension extension,const std::string & deviceName)185 bool TypeManager::registerExtension(Extension extension, const std::string& deviceName) {
186 if (mDisabledExtensions.find(extension.name) != mDisabledExtensions.end()) {
187 LOG(ERROR) << "Extension " << extension.name << " is disabled";
188 return false;
189 }
190
191 std::sort(extension.operandTypes.begin(), extension.operandTypes.end(),
192 [](const Extension::OperandTypeInformation& a,
193 const Extension::OperandTypeInformation& b) {
194 return static_cast<uint16_t>(a.type) < static_cast<uint16_t>(b.type);
195 });
196
197 std::map<std::string, Extension>::iterator it;
198 bool isNew;
199 std::tie(it, isNew) = mExtensionNameToExtension.emplace(extension.name, extension);
200 if (isNew) {
201 VLOG(MANAGER) << "Registered extension " << extension.name;
202 mExtensionNameToFirstDevice.emplace(extension.name, deviceName);
203 } else if (!equal(extension, it->second)) {
204 LOG(ERROR) << "Devices " << mExtensionNameToFirstDevice[extension.name] << " and "
205 << deviceName << " provide inconsistent information for extension "
206 << extension.name << ", which is therefore disabled";
207 mExtensionNameToExtension.erase(it);
208 mDisabledExtensions.insert(extension.name);
209 return false;
210 }
211 return true;
212 }
213
getExtensionPrefix(const std::string & extensionName,uint16_t * prefix)214 bool TypeManager::getExtensionPrefix(const std::string& extensionName, uint16_t* prefix) {
215 auto it = mExtensionNameToPrefix.find(extensionName);
216 if (it != mExtensionNameToPrefix.end()) {
217 *prefix = it->second;
218 } else {
219 NN_RET_CHECK_LE(mPrefixToExtension.size(), kMaxPrefix) << "Too many extensions in use";
220 *prefix = mPrefixToExtension.size();
221 mExtensionNameToPrefix[extensionName] = *prefix;
222 mPrefixToExtension.push_back(&mExtensionNameToExtension[extensionName]);
223 }
224 return true;
225 }
226
getExtensionType(const char * extensionName,uint16_t typeWithinExtension,int32_t * type)227 bool TypeManager::getExtensionType(const char* extensionName, uint16_t typeWithinExtension,
228 int32_t* type) {
229 uint16_t prefix;
230 NN_RET_CHECK(getExtensionPrefix(extensionName, &prefix));
231 *type = (prefix << kExtensionTypeBits) | typeWithinExtension;
232 return true;
233 }
234
getExtensionInfo(uint16_t prefix,const Extension ** extension) const235 bool TypeManager::getExtensionInfo(uint16_t prefix, const Extension** extension) const {
236 NN_RET_CHECK_NE(prefix, 0u) << "prefix=0 does not correspond to an extension";
237 NN_RET_CHECK_LT(prefix, mPrefixToExtension.size()) << "Unknown extension prefix";
238 *extension = mPrefixToExtension[prefix];
239 return true;
240 }
241
getExtensionOperandTypeInfo(OperandType type,const Extension::OperandTypeInformation ** info) const242 bool TypeManager::getExtensionOperandTypeInfo(
243 OperandType type, const Extension::OperandTypeInformation** info) const {
244 uint32_t operandType = static_cast<uint32_t>(type);
245 uint16_t prefix = operandType >> kExtensionTypeBits;
246 uint16_t typeWithinExtension = operandType & ((1 << kExtensionTypeBits) - 1);
247 const Extension* extension;
248 NN_RET_CHECK(getExtensionInfo(prefix, &extension))
249 << "Cannot find extension corresponding to prefix " << prefix;
250 auto it = std::lower_bound(
251 extension->operandTypes.begin(), extension->operandTypes.end(), typeWithinExtension,
252 [](const Extension::OperandTypeInformation& info, uint32_t typeSought) {
253 return static_cast<uint16_t>(info.type) < typeSought;
254 });
255 NN_RET_CHECK(it != extension->operandTypes.end() &&
256 static_cast<uint16_t>(it->type) == typeWithinExtension)
257 << "Cannot find operand type " << typeWithinExtension << " in extension "
258 << extension->name;
259 *info = &*it;
260 return true;
261 }
262
isTensorType(OperandType type) const263 bool TypeManager::isTensorType(OperandType type) const {
264 if (!isExtension(type)) {
265 return !nonExtensionOperandTypeIsScalar(static_cast<int>(type));
266 }
267 const Extension::OperandTypeInformation* info;
268 CHECK(getExtensionOperandTypeInfo(type, &info));
269 return info->isTensor;
270 }
271
getSizeOfData(OperandType type,const std::vector<uint32_t> & dimensions) const272 uint32_t TypeManager::getSizeOfData(OperandType type,
273 const std::vector<uint32_t>& dimensions) const {
274 if (!isExtension(type)) {
275 return nonExtensionOperandSizeOfData(type, dimensions);
276 }
277 const Extension::OperandTypeInformation* info;
278 CHECK(getExtensionOperandTypeInfo(type, &info));
279 return info->isTensor ? sizeOfTensorData(info->byteSize, dimensions) : info->byteSize;
280 }
281
sizeOfDataOverflowsUInt32(OperandType type,const std::vector<uint32_t> & dimensions) const282 bool TypeManager::sizeOfDataOverflowsUInt32(OperandType type,
283 const std::vector<uint32_t>& dimensions) const {
284 if (!isExtension(type)) {
285 return nonExtensionOperandSizeOfDataOverflowsUInt32(type, dimensions);
286 }
287 const Extension::OperandTypeInformation* info;
288 CHECK(getExtensionOperandTypeInfo(type, &info));
289 return info->isTensor ? sizeOfTensorDataOverflowsUInt32(info->byteSize, dimensions) : false;
290 }
291
292 } // namespace nn
293 } // namespace android
294