• 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 
21 #include "Utils.h"
22 
23 #include <android-base/file.h>
24 #include <android-base/properties.h>
25 #include <android/content/pm/IPackageManagerNative.h>
26 #include <binder/IServiceManager.h>
27 #include <procpartition/procpartition.h>
28 #include <algorithm>
29 #include <string_view>
30 
31 namespace android {
32 namespace nn {
33 
34 // Replacement function for std::string_view::starts_with()
35 // which shall be available in C++20.
36 #if __cplusplus >= 202000L
37 #error "When upgrading to C++20, remove this error and file a bug to remove this workaround."
38 #endif
StartsWith(std::string_view sv,std::string_view prefix)39 inline bool StartsWith(std::string_view sv, std::string_view prefix) {
40     return sv.substr(0u, prefix.size()) == prefix;
41 }
42 
43 namespace {
44 
45 const uint8_t kLowBitsType = static_cast<uint8_t>(Model::ExtensionTypeEncoding::LOW_BITS_TYPE);
46 const uint32_t kMaxPrefix =
47         (1 << static_cast<uint8_t>(Model::ExtensionTypeEncoding::HIGH_BITS_PREFIX)) - 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 // Property for disabling NNAPI vendor extensions on product image (used on GSI /product image,
59 // which can't use NNAPI vendor extensions).
60 const char kVExtProductDeny[] = "ro.nnapi.extensions.deny_on_product";
isNNAPIVendorExtensionsUseAllowedInProductImage()61 bool isNNAPIVendorExtensionsUseAllowedInProductImage() {
62     const std::string vExtProductDeny = android::base::GetProperty(kVExtProductDeny, "");
63     return vExtProductDeny.empty();
64 }
65 
66 // The file containing the list of Android apps and binaries allowed to use vendor extensions.
67 // Each line of the file contains new entry. If entry is prefixed by
68 // '/' slash, then it's a native binary path (e.g. '/data/foo'). If not, it's a name
69 // of Android app package (e.g. 'com.foo.bar').
70 const char kAppAllowlistPath[] = "/vendor/etc/nnapi_extensions_app_allowlist";
71 const char kCtsAllowlist[] = "/data/local/tmp/CTSNNAPITestCases";
getVendorExtensionAllowlistedApps()72 std::vector<std::string> getVendorExtensionAllowlistedApps() {
73     std::string data;
74     // Allowlist CTS by default.
75     std::vector<std::string> allowlist = {kCtsAllowlist};
76 
77     if (!android::base::ReadFileToString(kAppAllowlistPath, &data)) {
78         // Return default allowlist (no app can use extensions).
79         LOG(INFO) << "Failed to read " << kAppAllowlistPath
80                   << " ; No app allowlisted for vendor extensions use.";
81         return allowlist;
82     }
83 
84     std::istringstream streamData(data);
85     std::string line;
86     while (std::getline(streamData, line)) {
87         // Do some basic sanity check on entry, it's either
88         // fs path or package name.
89         if (StartsWith(line, "/") || line.find('.') != std::string::npos) {
90             allowlist.push_back(line);
91         } else {
92             LOG(ERROR) << kAppAllowlistPath << " - Invalid entry: " << line;
93         }
94     }
95     return allowlist;
96 }
97 
98 // Query PackageManagerNative service about Android app properties.
99 // On success, it will populate appPackageInfo->app* fields.
fetchAppPackageLocationInfo(uid_t uid,TypeManager::AppPackageInfo * appPackageInfo)100 bool fetchAppPackageLocationInfo(uid_t uid, TypeManager::AppPackageInfo* appPackageInfo) {
101     sp<::android::IServiceManager> sm(::android::defaultServiceManager());
102     sp<::android::IBinder> binder(sm->getService(String16("package_native")));
103     if (binder == nullptr) {
104         LOG(ERROR) << "getService package_native failed";
105         return false;
106     }
107 
108     sp<content::pm::IPackageManagerNative> packageMgr =
109             interface_cast<content::pm::IPackageManagerNative>(binder);
110     std::vector<int> uids{static_cast<int>(uid)};
111     std::vector<std::string> names;
112     binder::Status status = packageMgr->getNamesForUids(uids, &names);
113     if (!status.isOk()) {
114         LOG(ERROR) << "package_native::getNamesForUids failed: "
115                    << status.exceptionMessage().c_str();
116         return false;
117     }
118     const std::string& packageName = names[0];
119 
120     appPackageInfo->appPackageName = packageName;
121     int flags = 0;
122     status = packageMgr->getLocationFlags(packageName, &flags);
123     if (!status.isOk()) {
124         LOG(ERROR) << "package_native::getLocationFlags failed: "
125                    << status.exceptionMessage().c_str();
126         return false;
127     }
128     // isSystemApp()
129     appPackageInfo->appIsSystemApp =
130             ((flags & content::pm::IPackageManagerNative::LOCATION_SYSTEM) != 0);
131     // isVendor()
132     appPackageInfo->appIsOnVendorImage =
133             ((flags & content::pm::IPackageManagerNative::LOCATION_VENDOR) != 0);
134     // isProduct()
135     appPackageInfo->appIsOnProductImage =
136             ((flags & content::pm::IPackageManagerNative::LOCATION_PRODUCT) != 0);
137     return true;
138 }
139 
140 // Check if this process is allowed to use NNAPI Vendor extensions.
isNNAPIVendorExtensionsUseAllowed(const std::vector<std::string> & allowlist)141 bool isNNAPIVendorExtensionsUseAllowed(const std::vector<std::string>& allowlist) {
142     TypeManager::AppPackageInfo appPackageInfo = {
143             .binaryPath = ::android::procpartition::getExe(getpid()),
144             .appPackageName = "",
145             .appIsSystemApp = false,
146             .appIsOnVendorImage = false,
147             .appIsOnProductImage = false};
148 
149     if (appPackageInfo.binaryPath == "/system/bin/app_process64" ||
150         appPackageInfo.binaryPath == "/system/bin/app_process32") {
151         if (!fetchAppPackageLocationInfo(getuid(), &appPackageInfo)) {
152             LOG(ERROR) << "Failed to get app information from package_manager_native";
153             return false;
154         }
155     }
156     return TypeManager::isExtensionsUseAllowed(
157             appPackageInfo, isNNAPIVendorExtensionsUseAllowedInProductImage(), allowlist);
158 }
159 
160 }  // namespace
161 
TypeManager()162 TypeManager::TypeManager() {
163     VLOG(MANAGER) << "TypeManager::TypeManager";
164     mExtensionsAllowed = isNNAPIVendorExtensionsUseAllowed(getVendorExtensionAllowlistedApps());
165     VLOG(MANAGER) << "NNAPI Vendor extensions enabled: " << mExtensionsAllowed;
166     findAvailableExtensions();
167 }
168 
isExtensionsUseAllowed(const AppPackageInfo & appPackageInfo,bool useOnProductImageEnabled,const std::vector<std::string> & allowlist)169 bool TypeManager::isExtensionsUseAllowed(const AppPackageInfo& appPackageInfo,
170                                          bool useOnProductImageEnabled,
171                                          const std::vector<std::string>& allowlist) {
172     // Only selected partitions and user-installed apps (/data)
173     // are allowed to use extensions.
174     if (StartsWith(appPackageInfo.binaryPath, "/vendor/") ||
175         StartsWith(appPackageInfo.binaryPath, "/odm/") ||
176         StartsWith(appPackageInfo.binaryPath, "/data/") ||
177         (StartsWith(appPackageInfo.binaryPath, "/product/") && useOnProductImageEnabled)) {
178 #ifdef NN_DEBUGGABLE
179         // Only on userdebug and eng builds.
180         // When running tests with mma and adb push.
181         if (StartsWith(appPackageInfo.binaryPath, "/data/nativetest") ||
182             // When running tests with Atest.
183             StartsWith(appPackageInfo.binaryPath, "/data/local/tmp/NeuralNetworksTest_")) {
184             return true;
185         }
186 #endif  // NN_DEBUGGABLE
187 
188         return std::find(allowlist.begin(), allowlist.end(), appPackageInfo.binaryPath) !=
189                allowlist.end();
190     } else if (appPackageInfo.binaryPath == "/system/bin/app_process64" ||
191                appPackageInfo.binaryPath == "/system/bin/app_process32") {
192         // App is not system app OR vendor app OR (product app AND product enabled)
193         // AND app is on allowlist.
194         return (!appPackageInfo.appIsSystemApp || appPackageInfo.appIsOnVendorImage ||
195                 (appPackageInfo.appIsOnProductImage && useOnProductImageEnabled)) &&
196                std::find(allowlist.begin(), allowlist.end(), appPackageInfo.appPackageName) !=
197                        allowlist.end();
198     }
199     return false;
200 }
201 
findAvailableExtensions()202 void TypeManager::findAvailableExtensions() {
203     for (const std::shared_ptr<Device>& device : mDeviceManager->getDrivers()) {
204         for (const Extension extension : device->getSupportedExtensions()) {
205             registerExtension(extension, device->getName());
206         }
207     }
208 }
209 
registerExtension(Extension extension,const std::string & deviceName)210 bool TypeManager::registerExtension(Extension extension, const std::string& deviceName) {
211     if (mDisabledExtensions.find(extension.name) != mDisabledExtensions.end()) {
212         LOG(ERROR) << "Extension " << extension.name << " is disabled";
213         return false;
214     }
215 
216     std::sort(extension.operandTypes.begin(), extension.operandTypes.end(),
217               [](const Extension::OperandTypeInformation& a,
218                  const Extension::OperandTypeInformation& b) {
219                   return static_cast<uint16_t>(a.type) < static_cast<uint16_t>(b.type);
220               });
221 
222     std::map<std::string, Extension>::iterator it;
223     bool isNew;
224     std::tie(it, isNew) = mExtensionNameToExtension.emplace(extension.name, extension);
225     if (isNew) {
226         VLOG(MANAGER) << "Registered extension " << extension.name;
227         mExtensionNameToFirstDevice.emplace(extension.name, deviceName);
228     } else if (!equal(extension, it->second)) {
229         LOG(ERROR) << "Devices " << mExtensionNameToFirstDevice[extension.name] << " and "
230                    << deviceName << " provide inconsistent information for extension "
231                    << extension.name << ", which is therefore disabled";
232         mExtensionNameToExtension.erase(it);
233         mDisabledExtensions.insert(extension.name);
234         return false;
235     }
236     return true;
237 }
238 
getExtensionPrefix(const std::string & extensionName,uint16_t * prefix)239 bool TypeManager::getExtensionPrefix(const std::string& extensionName, uint16_t* prefix) {
240     auto it = mExtensionNameToPrefix.find(extensionName);
241     if (it != mExtensionNameToPrefix.end()) {
242         *prefix = it->second;
243     } else {
244         NN_RET_CHECK_LE(mPrefixToExtension.size(), kMaxPrefix) << "Too many extensions in use";
245         *prefix = mPrefixToExtension.size();
246         mExtensionNameToPrefix[extensionName] = *prefix;
247         mPrefixToExtension.push_back(&mExtensionNameToExtension[extensionName]);
248     }
249     return true;
250 }
251 
getExtensionType(const char * extensionName,uint16_t typeWithinExtension,int32_t * type)252 bool TypeManager::getExtensionType(const char* extensionName, uint16_t typeWithinExtension,
253                                    int32_t* type) {
254     uint16_t prefix;
255     NN_RET_CHECK(getExtensionPrefix(extensionName, &prefix));
256     *type = (prefix << kLowBitsType) | typeWithinExtension;
257     return true;
258 }
259 
getExtensionInfo(uint16_t prefix,const Extension ** extension) const260 bool TypeManager::getExtensionInfo(uint16_t prefix, const Extension** extension) const {
261     NN_RET_CHECK_NE(prefix, 0u) << "prefix=0 does not correspond to an extension";
262     NN_RET_CHECK_LT(prefix, mPrefixToExtension.size()) << "Unknown extension prefix";
263     *extension = mPrefixToExtension[prefix];
264     return true;
265 }
266 
getExtensionOperandTypeInfo(OperandType type,const Extension::OperandTypeInformation ** info) const267 bool TypeManager::getExtensionOperandTypeInfo(
268         OperandType type, const Extension::OperandTypeInformation** info) const {
269     uint32_t operandType = static_cast<uint32_t>(type);
270     uint16_t prefix = operandType >> kLowBitsType;
271     uint16_t typeWithinExtension = operandType & ((1 << kLowBitsType) - 1);
272     const Extension* extension;
273     NN_RET_CHECK(getExtensionInfo(prefix, &extension))
274             << "Cannot find extension corresponding to prefix " << prefix;
275     auto it = std::lower_bound(
276             extension->operandTypes.begin(), extension->operandTypes.end(), typeWithinExtension,
277             [](const Extension::OperandTypeInformation& info, uint32_t typeSought) {
278                 return static_cast<uint16_t>(info.type) < typeSought;
279             });
280     NN_RET_CHECK(it != extension->operandTypes.end() &&
281                  static_cast<uint16_t>(it->type) == typeWithinExtension)
282             << "Cannot find operand type " << typeWithinExtension << " in extension "
283             << extension->name;
284     *info = &*it;
285     return true;
286 }
287 
isTensorType(OperandType type) const288 bool TypeManager::isTensorType(OperandType type) const {
289     if (!isExtensionOperandType(type)) {
290         return !nonExtensionOperandTypeIsScalar(static_cast<int>(type));
291     }
292     const Extension::OperandTypeInformation* info;
293     CHECK(getExtensionOperandTypeInfo(type, &info));
294     return info->isTensor;
295 }
296 
getSizeOfData(OperandType type,const std::vector<uint32_t> & dimensions) const297 uint32_t TypeManager::getSizeOfData(OperandType type,
298                                     const std::vector<uint32_t>& dimensions) const {
299     if (!isExtensionOperandType(type)) {
300         return nonExtensionOperandSizeOfData(type, dimensions);
301     }
302 
303     const Extension::OperandTypeInformation* info;
304     CHECK(getExtensionOperandTypeInfo(type, &info));
305 
306     if (!info->isTensor) {
307         return info->byteSize;
308     }
309 
310     if (dimensions.empty()) {
311         return 0;
312     }
313 
314     uint32_t size = info->byteSize;
315     for (auto dimension : dimensions) {
316         size *= dimension;
317     }
318     return size;
319 }
320 
321 }  // namespace nn
322 }  // namespace android
323