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