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