blob: 650d21785ec2c0277c7b2039c1655d38b36359ce [file] [log] [blame]
Jesse Hall79bf3922016-12-12 12:53:02 -08001/*
2 * Copyright 2016 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
17package android.os;
18
Tim Van Pattenddc43912018-12-18 17:47:52 -070019import android.content.ContentResolver;
Jesse Hall79bf3922016-12-12 12:53:02 -080020import android.content.Context;
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -070021import android.content.Intent;
Jesse Hall79bf3922016-12-12 12:53:02 -080022import android.content.pm.ApplicationInfo;
Yiwei Zhang33097bf2019-02-04 19:01:21 -080023import android.content.pm.PackageInfo;
Jesse Hall79bf3922016-12-12 12:53:02 -080024import android.content.pm.PackageManager;
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -070025import android.content.pm.ResolveInfo;
Cody Northrop7fd44212018-09-06 10:30:28 -060026import android.content.res.AssetFileDescriptor;
Peiyong Lin88c38eb2018-10-12 15:34:15 -070027import android.content.res.AssetManager;
Cody Northrop86cedcb2017-10-20 09:03:13 -060028import android.provider.Settings;
Jesse Hall79bf3922016-12-12 12:53:02 -080029import android.util.Log;
Tim Van Pattenddc43912018-12-18 17:47:52 -070030import android.widget.Toast;
Jesse Hall79bf3922016-12-12 12:53:02 -080031
32import dalvik.system.VMRuntime;
33
34import java.io.File;
Cody Northrop7fd44212018-09-06 10:30:28 -060035import java.io.FileDescriptor;
Cody Northrop8d72a6b2018-11-01 08:20:26 -060036import java.io.FileInputStream;
37import java.io.FileNotFoundException;
Peiyong Lin88c38eb2018-10-12 15:34:15 -070038import java.io.IOException;
Tim Van Patten3c612842018-11-09 16:48:24 -070039import java.util.ArrayList;
40import java.util.Arrays;
41import java.util.HashMap;
42import java.util.List;
43import java.util.Map;
Jesse Hall79bf3922016-12-12 12:53:02 -080044
45/** @hide */
Cody Northrop86cedcb2017-10-20 09:03:13 -060046public class GraphicsEnvironment {
47
48 private static final GraphicsEnvironment sInstance = new GraphicsEnvironment();
49
50 /**
51 * Returns the shared {@link GraphicsEnvironment} instance.
52 */
53 public static GraphicsEnvironment getInstance() {
54 return sInstance;
55 }
Jesse Hall79bf3922016-12-12 12:53:02 -080056
57 private static final boolean DEBUG = false;
58 private static final String TAG = "GraphicsEnvironment";
Yiwei Zhang33097bf2019-02-04 19:01:21 -080059 private static final String SYSTEM_DRIVER_NAME = "system";
60 private static final String SYSTEM_DRIVER_VERSION_NAME = "";
61 private static final long SYSTEM_DRIVER_VERSION_CODE = 0;
Jesse Hall79bf3922016-12-12 12:53:02 -080062 private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
Yiwei Zhangf7b0a5f2019-02-19 16:04:10 -080063 private static final String PROPERTY_GFX_DRIVER_BUILD_TIME = "ro.gfx.driver_build_time";
64 private static final String METADATA_DRIVER_BUILD_TIME = "driver_build_time";
Cody Northrop7fd44212018-09-06 10:30:28 -060065 private static final String ANGLE_RULES_FILE = "a4a_rules.json";
Cody Northrop8d72a6b2018-11-01 08:20:26 -060066 private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -070067 private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID";
Peiyong Linb76bfe92019-02-13 14:46:54 -080068 private static final String GAME_DRIVER_WHITELIST_ALL = "*";
Jesse Hall79bf3922016-12-12 12:53:02 -080069
Cody Northrop86cedcb2017-10-20 09:03:13 -060070 private ClassLoader mClassLoader;
71 private String mLayerPath;
72 private String mDebugLayerPath;
73
74 /**
75 * Set up GraphicsEnvironment
76 */
Cody Northropdeb43282018-10-04 16:04:05 -060077 public void setup(Context context, Bundle coreSettings) {
Yiwei Zhang33097bf2019-02-04 19:01:21 -080078 final PackageManager pm = context.getPackageManager();
79 final String packageName = context.getPackageName();
80 setupGpuLayers(context, coreSettings, pm, packageName);
81 setupAngle(context, coreSettings, pm, packageName);
82 if (!chooseDriver(context, coreSettings, pm, packageName)) {
83 setGpuStats(SYSTEM_DRIVER_NAME, SYSTEM_DRIVER_VERSION_NAME, SYSTEM_DRIVER_VERSION_CODE,
Yiwei Zhangf7b0a5f2019-02-19 16:04:10 -080084 SystemProperties.getLong(PROPERTY_GFX_DRIVER_BUILD_TIME, 0), packageName);
Yiwei Zhang33097bf2019-02-04 19:01:21 -080085 }
Cody Northrop86cedcb2017-10-20 09:03:13 -060086 }
87
88 /**
89 * Check whether application is debuggable
90 */
91 private static boolean isDebuggable(Context context) {
92 return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) > 0;
93 }
94
95 /**
96 * Store the layer paths available to the loader.
97 */
98 public void setLayerPaths(ClassLoader classLoader,
99 String layerPath,
100 String debugLayerPath) {
101 // We have to store these in the class because they are set up before we
102 // have access to the Context to properly set up GraphicsEnvironment
103 mClassLoader = classLoader;
104 mLayerPath = layerPath;
105 mDebugLayerPath = debugLayerPath;
106 }
107
108 /**
Cody Northropebe6a562018-10-15 07:22:23 -0600109 * Return the debug layer app's on-disk and in-APK lib directories
110 */
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800111 private static String getDebugLayerAppPaths(PackageManager pm, String app) {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800112 final ApplicationInfo appInfo;
Cody Northropebe6a562018-10-15 07:22:23 -0600113 try {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800114 appInfo = pm.getApplicationInfo(app, PackageManager.MATCH_ALL);
Cody Northropebe6a562018-10-15 07:22:23 -0600115 } catch (PackageManager.NameNotFoundException e) {
116 Log.w(TAG, "Debug layer app '" + app + "' not installed");
117
118 return null;
119 }
120
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800121 final String abi = chooseAbi(appInfo);
Cody Northropebe6a562018-10-15 07:22:23 -0600122
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800123 final StringBuilder sb = new StringBuilder();
Cody Northropebe6a562018-10-15 07:22:23 -0600124 sb.append(appInfo.nativeLibraryDir)
125 .append(File.pathSeparator);
126 sb.append(appInfo.sourceDir)
127 .append("!/lib/")
128 .append(abi);
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800129 final String paths = sb.toString();
Cody Northropebe6a562018-10-15 07:22:23 -0600130
131 if (DEBUG) Log.v(TAG, "Debug layer app libs: " + paths);
132
133 return paths;
134 }
135
136 /**
Cody Northrop86cedcb2017-10-20 09:03:13 -0600137 * Set up layer search paths for all apps
138 * If debuggable, check for additional debug settings
139 */
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800140 private void setupGpuLayers(
141 Context context, Bundle coreSettings, PackageManager pm, String packageName) {
Cody Northrop86cedcb2017-10-20 09:03:13 -0600142 String layerPaths = "";
143
144 // Only enable additional debug functionality if the following conditions are met:
Cody Northropebe6a562018-10-15 07:22:23 -0600145 // 1. App is debuggable or device is rooted
Cody Northrop86cedcb2017-10-20 09:03:13 -0600146 // 2. ENABLE_GPU_DEBUG_LAYERS is true
147 // 3. Package name is equal to GPU_DEBUG_APP
148
Cody Northropebe6a562018-10-15 07:22:23 -0600149 if (isDebuggable(context) || (getCanLoadSystemLibraries() == 1)) {
Cody Northrop86cedcb2017-10-20 09:03:13 -0600150
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800151 final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600152
153 if (enable != 0) {
154
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800155 final String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600156
Cody Northrop86cedcb2017-10-20 09:03:13 -0600157 if ((gpuDebugApp != null && packageName != null)
158 && (!gpuDebugApp.isEmpty() && !packageName.isEmpty())
159 && gpuDebugApp.equals(packageName)) {
160 Log.i(TAG, "GPU debug layers enabled for " + packageName);
161
162 // Prepend the debug layer path as a searchable path.
163 // This will ensure debug layers added will take precedence over
164 // the layers specified by the app.
165 layerPaths = mDebugLayerPath + ":";
166
Cody Northropebe6a562018-10-15 07:22:23 -0600167 // If there is a debug layer app specified, add its path.
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800168 final String gpuDebugLayerApp =
Cody Northropebe6a562018-10-15 07:22:23 -0600169 coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP);
170
171 if (gpuDebugLayerApp != null && !gpuDebugLayerApp.isEmpty()) {
172 Log.i(TAG, "GPU debug layer app: " + gpuDebugLayerApp);
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800173 final String paths = getDebugLayerAppPaths(pm, gpuDebugLayerApp);
Cody Northropebe6a562018-10-15 07:22:23 -0600174 if (paths != null) {
175 // Append the path so files placed in the app's base directory will
176 // override the external path
177 layerPaths += paths + ":";
178 }
179 }
180
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800181 final String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600182
Cody Northrop0fa1d222018-10-23 13:13:21 -0600183 Log.i(TAG, "Vulkan debug layer list: " + layers);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600184 if (layers != null && !layers.isEmpty()) {
185 setDebugLayers(layers);
186 }
Cody Northrop0fa1d222018-10-23 13:13:21 -0600187
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800188 final String layersGLES =
Cody Northrop0fa1d222018-10-23 13:13:21 -0600189 coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS_GLES);
190
191 Log.i(TAG, "GLES debug layer list: " + layersGLES);
192 if (layersGLES != null && !layersGLES.isEmpty()) {
193 setDebugLayersGLES(layersGLES);
194 }
Cody Northrop86cedcb2017-10-20 09:03:13 -0600195 }
196 }
Cody Northrop86cedcb2017-10-20 09:03:13 -0600197 }
198
199 // Include the app's lib directory in all cases
200 layerPaths += mLayerPath;
201
202 setLayerPaths(mClassLoader, layerPaths);
203 }
204
Tim Van Patten3c612842018-11-09 16:48:24 -0700205 enum OpenGlDriverChoice {
206 DEFAULT,
207 NATIVE,
208 ANGLE
209 }
210
211 private static final Map<OpenGlDriverChoice, String> sDriverMap = buildMap();
212 private static Map<OpenGlDriverChoice, String> buildMap() {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800213 final Map<OpenGlDriverChoice, String> map = new HashMap<>();
Tim Van Patten3c612842018-11-09 16:48:24 -0700214 map.put(OpenGlDriverChoice.DEFAULT, "default");
215 map.put(OpenGlDriverChoice.ANGLE, "angle");
216 map.put(OpenGlDriverChoice.NATIVE, "native");
217
218 return map;
219 }
220
221
Tim Van Pattenddc43912018-12-18 17:47:52 -0700222 private static List<String> getGlobalSettingsString(ContentResolver contentResolver,
223 Bundle bundle,
224 String globalSetting) {
225 final List<String> valueList;
226 final String settingsValue;
227
228 if (bundle != null) {
229 settingsValue = bundle.getString(globalSetting);
230 } else {
231 settingsValue = Settings.Global.getString(contentResolver, globalSetting);
232 }
Tim Van Patten3c612842018-11-09 16:48:24 -0700233
234 if (settingsValue != null) {
235 valueList = new ArrayList<>(Arrays.asList(settingsValue.split(",")));
236 } else {
237 valueList = new ArrayList<>();
238 }
239
240 return valueList;
241 }
242
243 private static int getGlobalSettingsPkgIndex(String pkgName,
244 List<String> globalSettingsDriverPkgs) {
245 for (int pkgIndex = 0; pkgIndex < globalSettingsDriverPkgs.size(); pkgIndex++) {
246 if (globalSettingsDriverPkgs.get(pkgIndex).equals(pkgName)) {
247 return pkgIndex;
248 }
249 }
250
251 return -1;
252 }
253
Tim Van Pattenddc43912018-12-18 17:47:52 -0700254 private static String getDriverForPkg(Context context, Bundle bundle, String packageName) {
255 final String allUseAngle;
256 if (bundle != null) {
257 allUseAngle =
258 bundle.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
259 } else {
260 ContentResolver contentResolver = context.getContentResolver();
261 allUseAngle = Settings.Global.getString(contentResolver,
262 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
263 }
Tim Van Pattenff9476b2018-12-11 15:41:25 -0700264 if ((allUseAngle != null) && allUseAngle.equals("1")) {
265 return sDriverMap.get(OpenGlDriverChoice.ANGLE);
Tim Van Patten3c612842018-11-09 16:48:24 -0700266 }
267
Tim Van Pattenddc43912018-12-18 17:47:52 -0700268 final ContentResolver contentResolver = context.getContentResolver();
269 final List<String> globalSettingsDriverPkgs =
270 getGlobalSettingsString(contentResolver, bundle,
271 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS);
272 final List<String> globalSettingsDriverValues =
273 getGlobalSettingsString(contentResolver, bundle,
274 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES);
Tim Van Patten3c612842018-11-09 16:48:24 -0700275
276 // Make sure we have a good package name
277 if ((packageName == null) || (packageName.isEmpty())) {
278 return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
279 }
280 // Make sure we have good settings to use
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700281 if (globalSettingsDriverPkgs.size() != globalSettingsDriverValues.size()) {
Tim Van Patten3c612842018-11-09 16:48:24 -0700282 Log.w(TAG,
283 "Global.Settings values are invalid: "
284 + "globalSettingsDriverPkgs.size = "
285 + globalSettingsDriverPkgs.size() + ", "
286 + "globalSettingsDriverValues.size = "
287 + globalSettingsDriverValues.size());
288 return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
289 }
290
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800291 final int pkgIndex = getGlobalSettingsPkgIndex(packageName, globalSettingsDriverPkgs);
Tim Van Patten3c612842018-11-09 16:48:24 -0700292
293 if (pkgIndex < 0) {
294 return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
295 }
296
297 return globalSettingsDriverValues.get(pkgIndex);
298 }
299
Jesse Hallc37984f2017-05-23 16:55:08 -0700300 /**
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700301 * Get the ANGLE package name.
302 */
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800303 private String getAnglePackageName(PackageManager pm) {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800304 final Intent intent = new Intent(ACTION_ANGLE_FOR_ANDROID);
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700305
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800306 final List<ResolveInfo> resolveInfos =
307 pm.queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700308 if (resolveInfos.size() != 1) {
309 Log.e(TAG, "Invalid number of ANGLE packages. Required: 1, Found: "
310 + resolveInfos.size());
311 for (ResolveInfo resolveInfo : resolveInfos) {
312 Log.e(TAG, "Found ANGLE package: " + resolveInfo.activityInfo.packageName);
313 }
314 return "";
315 }
316
317 // Must be exactly 1 ANGLE PKG found to get here.
318 return resolveInfos.get(0).activityInfo.packageName;
319 }
320
321 /**
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700322 * Attempt to setup ANGLE with a temporary rules file.
323 * True: Temporary rules file was loaded.
324 * False: Temporary rules file was *not* loaded.
325 */
Tim Van Pattenddc43912018-12-18 17:47:52 -0700326 private static boolean setupAngleWithTempRulesFile(Context context,
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700327 String packageName,
328 String paths,
329 String devOptIn) {
Tim Van Patten3df66432019-01-14 15:56:12 -0700330 /**
331 * We only want to load a temp rules file for:
332 * - apps that are marked 'debuggable' in their manifest
333 * - devices that are running a userdebug build (ro.debuggable) or can inject libraries for
334 * debugging (PR_SET_DUMPABLE).
335 */
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800336 final boolean appIsDebuggable = isDebuggable(context);
337 final boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
Tim Van Patten3df66432019-01-14 15:56:12 -0700338 if (!(appIsDebuggable || deviceIsDebuggable)) {
339 Log.v(TAG, "Skipping loading temporary rules file: "
340 + "appIsDebuggable = " + appIsDebuggable + ", "
341 + "adbRootEnabled = " + deviceIsDebuggable);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700342 return false;
343 }
344
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800345 final String angleTempRules = SystemProperties.get(ANGLE_TEMP_RULES);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700346
347 if ((angleTempRules == null) || angleTempRules.isEmpty()) {
348 Log.v(TAG, "System property '" + ANGLE_TEMP_RULES + "' is not set or is empty");
349 return false;
350 }
351
352 Log.i(TAG, "Detected system property " + ANGLE_TEMP_RULES + ": " + angleTempRules);
353
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800354 final File tempRulesFile = new File(angleTempRules);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700355 if (tempRulesFile.exists()) {
356 Log.i(TAG, angleTempRules + " exists, loading file.");
357 try {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800358 final FileInputStream stream = new FileInputStream(angleTempRules);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700359
360 try {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800361 final FileDescriptor rulesFd = stream.getFD();
362 final long rulesOffset = 0;
363 final long rulesLength = stream.getChannel().size();
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700364 Log.i(TAG, "Loaded temporary ANGLE rules from " + angleTempRules);
365
366 setAngleInfo(paths, packageName, devOptIn, rulesFd, rulesOffset, rulesLength);
367
368 stream.close();
369
370 // We successfully setup ANGLE, so return with good status
371 return true;
372 } catch (IOException e) {
373 Log.w(TAG, "Hit IOException thrown by FileInputStream: " + e);
374 }
375 } catch (FileNotFoundException e) {
376 Log.w(TAG, "Temp ANGLE rules file not found: " + e);
377 } catch (SecurityException e) {
378 Log.w(TAG, "Temp ANGLE rules file not accessible: " + e);
379 }
380 }
381
382 return false;
383 }
384
385 /**
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700386 * Attempt to setup ANGLE with a rules file loaded from the ANGLE APK.
387 * True: APK rules file was loaded.
388 * False: APK rules file was *not* loaded.
389 */
Tim Van Pattenddc43912018-12-18 17:47:52 -0700390 private static boolean setupAngleRulesApk(String anglePkgName,
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700391 ApplicationInfo angleInfo,
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800392 PackageManager pm,
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700393 String packageName,
394 String paths,
395 String devOptIn) {
396 // Pass the rules file to loader for ANGLE decisions
397 try {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800398 final AssetManager angleAssets = pm.getResourcesForApplication(angleInfo).getAssets();
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700399
400 try {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800401 final AssetFileDescriptor assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700402
403 setAngleInfo(paths, packageName, devOptIn, assetsFd.getFileDescriptor(),
404 assetsFd.getStartOffset(), assetsFd.getLength());
405
406 assetsFd.close();
407
408 return true;
409 } catch (IOException e) {
410 Log.w(TAG, "Failed to get AssetFileDescriptor for " + ANGLE_RULES_FILE
411 + " from '" + anglePkgName + "': " + e);
412 }
413 } catch (PackageManager.NameNotFoundException e) {
414 Log.w(TAG, "Failed to get AssetManager for '" + anglePkgName + "': " + e);
415 }
416
417 return false;
418 }
419
420 /**
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700421 * Pull ANGLE whitelist from GlobalSettings and compare against current package
422 */
Tim Van Pattenddc43912018-12-18 17:47:52 -0700423 private static boolean checkAngleWhitelist(Context context, Bundle bundle, String packageName) {
424 final ContentResolver contentResolver = context.getContentResolver();
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800425 final List<String> angleWhitelist =
Tim Van Pattenddc43912018-12-18 17:47:52 -0700426 getGlobalSettingsString(contentResolver, bundle,
427 Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST);
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700428
429 return angleWhitelist.contains(packageName);
430 }
431
432 /**
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600433 * Pass ANGLE details down to trigger enable logic
Tim Van Pattenddc43912018-12-18 17:47:52 -0700434 *
435 * @param context
436 * @param bundle
437 * @param packageName
438 * @return true: ANGLE setup successfully
439 * false: ANGLE not setup (not on whitelist, ANGLE not present, etc.)
Cody Northrop73c05042018-04-16 13:23:51 -0600440 */
Tim Van Pattenddc43912018-12-18 17:47:52 -0700441 public boolean setupAngle(Context context, Bundle bundle, PackageManager pm,
442 String packageName) {
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700443 if (packageName.isEmpty()) {
444 Log.v(TAG, "No package name available yet, skipping ANGLE setup");
Tim Van Pattenddc43912018-12-18 17:47:52 -0700445 return false;
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700446 }
Cody Northrop73c05042018-04-16 13:23:51 -0600447
Tim Van Pattenddc43912018-12-18 17:47:52 -0700448 final String devOptIn = getDriverForPkg(context, bundle, packageName);
Tim Van Patten3c612842018-11-09 16:48:24 -0700449 if (DEBUG) {
450 Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
451 + "set to: '" + devOptIn + "'");
Cody Northrop841c3d92018-08-29 16:36:12 -0600452 }
453
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700454 // We only need to check rules if the app is whitelisted or the developer has
455 // explicitly chosen something other than default driver.
456 //
457 // The whitelist will be generated by the ANGLE APK at both boot time and
458 // ANGLE update time. It will only include apps mentioned in the rules file.
459 //
460 // If the user has set the developer option to something other than default,
461 // we need to call setupAngleRulesApk() with the package name and the developer
462 // option value (native/angle/other). Then later when we are actually trying to
463 // load a driver, GraphicsEnv::shouldUseAngle() has seen the package name before
464 // and can confidently answer yes/no based on the previously set developer
465 // option value.
Tim Van Pattenddc43912018-12-18 17:47:52 -0700466 final boolean whitelisted = checkAngleWhitelist(context, bundle, packageName);
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800467 final boolean defaulted = devOptIn.equals(sDriverMap.get(OpenGlDriverChoice.DEFAULT));
468 final boolean rulesCheck = (whitelisted || !defaulted);
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700469 if (!rulesCheck) {
Tim Van Pattenddc43912018-12-18 17:47:52 -0700470 return false;
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700471 }
472
473 if (whitelisted) {
474 Log.v(TAG, "ANGLE whitelist includes " + packageName);
475 }
476 if (!defaulted) {
477 Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
478 }
479
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800480 final String anglePkgName = getAnglePackageName(pm);
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700481 if (anglePkgName.isEmpty()) {
482 Log.e(TAG, "Failed to find ANGLE package.");
Tim Van Pattenddc43912018-12-18 17:47:52 -0700483 return false;
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700484 }
485
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800486 final ApplicationInfo angleInfo;
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600487 try {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800488 angleInfo = pm.getApplicationInfo(anglePkgName, PackageManager.MATCH_SYSTEM_ONLY);
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600489 } catch (PackageManager.NameNotFoundException e) {
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700490 Log.w(TAG, "ANGLE package '" + anglePkgName + "' not installed");
Tim Van Pattenddc43912018-12-18 17:47:52 -0700491 return false;
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600492 }
493
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800494 final String abi = chooseAbi(angleInfo);
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600495
496 // Build a path that includes installed native libs and APK
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800497 final String paths = angleInfo.nativeLibraryDir
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700498 + File.pathSeparator
499 + angleInfo.sourceDir
500 + "!/lib/"
501 + abi;
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600502
503 if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
504
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700505 if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) {
506 // We setup ANGLE with a temp rules file, so we're done here.
Tim Van Pattenddc43912018-12-18 17:47:52 -0700507 return true;
Cody Northrop8d72a6b2018-11-01 08:20:26 -0600508 }
509
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800510 if (setupAngleRulesApk(anglePkgName, angleInfo, pm, packageName, paths, devOptIn)) {
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700511 // We setup ANGLE with rules from the APK, so we're done here.
Tim Van Pattenddc43912018-12-18 17:47:52 -0700512 return true;
513 }
514
515 return false;
516 }
517
518 /**
519 * Determine if the "ANGLE In Use" dialog box should be shown.
520 */
521 private boolean shouldShowAngleInUseDialogBox(Context context) {
522 try {
523 ContentResolver contentResolver = context.getContentResolver();
524 final int showDialogBox = Settings.Global.getInt(contentResolver,
525 Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX);
526
527 return (showDialogBox == 1);
528 } catch (Settings.SettingNotFoundException | SecurityException e) {
529 // Do nothing and move on
530 }
531
532 // No setting, so assume false
533 return false;
534 }
535
536 /**
537 * Determine if ANGLE should be used.
538 */
539 private boolean shouldUseAngle(Context context, String packageName) {
540 // Need to make sure we are evaluating ANGLE usage for the correct circumstances
541 if (!setupAngle(context, null, context.getPackageManager(), packageName)) {
542 Log.v(TAG, "Package '" + packageName + "' should use not ANGLE");
543 return false;
544 }
545
546 final boolean useAngle = getShouldUseAngle(packageName);
547 Log.v(TAG, "Package '" + packageName + "' should use ANGLE = '" + useAngle + "'");
548
549 return useAngle;
550 }
551
552 /**
553 * Show the ANGLE in Use Dialog Box
554 * @param context
555 */
556 public void showAngleInUseDialogBox(Context context) {
557 final String packageName = context.getPackageName();
558
559 if (shouldShowAngleInUseDialogBox(context) && shouldUseAngle(context, packageName)) {
560 final String toastMsg = packageName + " is using ANGLE";
561 final Toast toast = Toast.makeText(context, toastMsg, Toast.LENGTH_LONG);
562 toast.show();
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700563 }
Cody Northrop73c05042018-04-16 13:23:51 -0600564 }
565
566 /**
Jesse Hallc37984f2017-05-23 16:55:08 -0700567 * Choose whether the current process should use the builtin or an updated driver.
Jesse Hallc37984f2017-05-23 16:55:08 -0700568 */
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800569 private static boolean chooseDriver(
570 Context context, Bundle coreSettings, PackageManager pm, String packageName) {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800571 final String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER);
Jesse Hall79bf3922016-12-12 12:53:02 -0800572 if (driverPackageName == null || driverPackageName.isEmpty()) {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800573 return false;
Jesse Hall79bf3922016-12-12 12:53:02 -0800574 }
Peiyong Lin2d5a2bb2018-11-07 21:10:07 -0800575
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800576 final PackageInfo driverPackageInfo;
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800577 try {
Yiwei Zhang31f5adb2019-02-15 16:15:17 -0800578 driverPackageInfo = pm.getPackageInfo(driverPackageName,
579 PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA);
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800580 } catch (PackageManager.NameNotFoundException e) {
581 Log.w(TAG, "driver package '" + driverPackageName + "' not installed");
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800582 return false;
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800583 }
584
585 // O drivers are restricted to the sphal linker namespace, so don't try to use
586 // packages unless they declare they're compatible with that restriction.
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800587 final ApplicationInfo driverAppInfo = driverPackageInfo.applicationInfo;
588 if (driverAppInfo.targetSdkVersion < Build.VERSION_CODES.O) {
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800589 if (DEBUG) {
590 Log.w(TAG, "updated driver package is not known to be compatible with O");
591 }
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800592 return false;
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800593 }
594
Jesse Hall79bf3922016-12-12 12:53:02 -0800595 // To minimize risk of driver updates crippling the device beyond user repair, never use an
596 // updated driver for privileged or non-updated system apps. Presumably pre-installed apps
597 // were tested thoroughly with the pre-installed driver.
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800598 final ApplicationInfo ai = context.getApplicationInfo();
Jesse Hall79bf3922016-12-12 12:53:02 -0800599 if (ai.isPrivilegedApp() || (ai.isSystemApp() && !ai.isUpdatedSystemApp())) {
600 if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app");
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800601 return false;
Jesse Hall79bf3922016-12-12 12:53:02 -0800602 }
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700603
Yiwei Zhang2b3be862019-01-24 14:45:53 -0800604 // GAME_DRIVER_ALL_APPS
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800605 // 0: Default (Invalid values fallback to default as well)
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800606 // 1: All apps use Game Driver
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800607 // 2: All apps use system graphics driver
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800608 final int gameDriverAllApps = coreSettings.getInt(Settings.Global.GAME_DRIVER_ALL_APPS, 0);
Yiwei Zhang2b3be862019-01-24 14:45:53 -0800609 if (gameDriverAllApps == 2) {
Peiyong Lin2d5a2bb2018-11-07 21:10:07 -0800610 if (DEBUG) {
Yiwei Zhang2b3be862019-01-24 14:45:53 -0800611 Log.w(TAG, "Game Driver is turned off on this device");
Yiwei Zhang51015a72018-12-29 03:47:56 +0800612 }
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800613 return false;
Yiwei Zhang51015a72018-12-29 03:47:56 +0800614 }
615
Yiwei Zhang2b3be862019-01-24 14:45:53 -0800616 if (gameDriverAllApps != 1) {
617 // GAME_DRIVER_OPT_OUT_APPS has higher priority than GAME_DRIVER_OPT_IN_APPS
Tim Van Pattenddc43912018-12-18 17:47:52 -0700618 if (getGlobalSettingsString(null, coreSettings,
619 Settings.Global.GAME_DRIVER_OPT_OUT_APPS).contains(packageName)) {
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800620 if (DEBUG) {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800621 Log.w(TAG, packageName + " opts out from Game Driver.");
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800622 }
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800623 return false;
Peiyong Lin2d5a2bb2018-11-07 21:10:07 -0800624 }
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800625 final boolean isOptIn =
Tim Van Pattenddc43912018-12-18 17:47:52 -0700626 getGlobalSettingsString(null, coreSettings,
627 Settings.Global.GAME_DRIVER_OPT_IN_APPS).contains(packageName);
Peiyong Linb76bfe92019-02-13 14:46:54 -0800628 final List<String> whitelist = getGlobalSettingsString(null, coreSettings,
629 Settings.Global.GAME_DRIVER_WHITELIST);
630 if (!isOptIn && whitelist.indexOf(GAME_DRIVER_WHITELIST_ALL) != 0
631 && !whitelist.contains(packageName)) {
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800632 if (DEBUG) {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800633 Log.w(TAG, packageName + " is not on the whitelist.");
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800634 }
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800635 return false;
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800636 }
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700637
Peiyong Lin24854202019-02-13 20:02:33 +0000638 // If the application is not opted-in and check whether it's on the blacklist,
639 // terminate early if it's on the blacklist and fallback to system driver.
640 if (!isOptIn
641 && getGlobalSettingsString(null, coreSettings,
642 Settings.Global.GAME_DRIVER_BLACKLIST)
643 .contains(ai.packageName)) {
644 return false;
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700645 }
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700646 }
647
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800648 final String abi = chooseAbi(driverAppInfo);
Jesse Hall79bf3922016-12-12 12:53:02 -0800649 if (abi == null) {
650 if (DEBUG) {
651 // This is the normal case for the pre-installed empty driver package, don't spam
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800652 if (driverAppInfo.isUpdatedSystemApp()) {
Jesse Hall79bf3922016-12-12 12:53:02 -0800653 Log.w(TAG, "updated driver package has no compatible native libraries");
654 }
655 }
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800656 return false;
Jesse Hall79bf3922016-12-12 12:53:02 -0800657 }
Jesse Hall79bf3922016-12-12 12:53:02 -0800658
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800659 final StringBuilder sb = new StringBuilder();
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800660 sb.append(driverAppInfo.nativeLibraryDir)
Jesse Hall79bf3922016-12-12 12:53:02 -0800661 .append(File.pathSeparator);
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800662 sb.append(driverAppInfo.sourceDir)
Jesse Hall79bf3922016-12-12 12:53:02 -0800663 .append("!/lib/")
664 .append(abi);
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800665 final String paths = sb.toString();
Jesse Hall79bf3922016-12-12 12:53:02 -0800666
Yiwei Zhang1c51f052019-02-14 12:05:47 -0800667 final String sphalLibraries =
668 coreSettings.getString(Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES);
669
670 if (DEBUG) {
671 Log.v(TAG,
672 "gfx driver package search path: " + paths
673 + ", required sphal libraries: " + sphalLibraries);
674 }
675 setDriverPathAndSphalLibraries(paths, sphalLibraries);
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800676
Yiwei Zhangf7b0a5f2019-02-19 16:04:10 -0800677 if (driverAppInfo.metaData == null) {
678 throw new NullPointerException("apk's meta-data cannot be null");
679 }
680
681 final String driverBuildTime = driverAppInfo.metaData.getString(METADATA_DRIVER_BUILD_TIME);
682 if (driverBuildTime == null || driverBuildTime.isEmpty()) {
683 throw new IllegalArgumentException("driver_build_time meta-data is not set");
684 }
685 // driver_build_time in the meta-data is in "L<Unix epoch timestamp>" format. e.g. L123456.
686 // Long.parseLong will throw if the meta-data "driver_build_time" is not set properly.
Yiwei Zhang31f5adb2019-02-15 16:15:17 -0800687 setGpuStats(driverPackageName, driverPackageInfo.versionName, driverAppInfo.longVersionCode,
Yiwei Zhangf7b0a5f2019-02-19 16:04:10 -0800688 Long.parseLong(driverBuildTime.substring(1)), packageName);
Yiwei Zhang31f5adb2019-02-15 16:15:17 -0800689
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800690 return true;
Jesse Hall79bf3922016-12-12 12:53:02 -0800691 }
692
Jesse Hall79bf3922016-12-12 12:53:02 -0800693 private static String chooseAbi(ApplicationInfo ai) {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800694 final String isa = VMRuntime.getCurrentInstructionSet();
Jesse Hall79bf3922016-12-12 12:53:02 -0800695 if (ai.primaryCpuAbi != null &&
696 isa.equals(VMRuntime.getInstructionSet(ai.primaryCpuAbi))) {
697 return ai.primaryCpuAbi;
698 }
699 if (ai.secondaryCpuAbi != null &&
700 isa.equals(VMRuntime.getInstructionSet(ai.secondaryCpuAbi))) {
701 return ai.secondaryCpuAbi;
702 }
703 return null;
704 }
705
Cody Northropebe6a562018-10-15 07:22:23 -0600706 private static native int getCanLoadSystemLibraries();
Cody Northrop86cedcb2017-10-20 09:03:13 -0600707 private static native void setLayerPaths(ClassLoader classLoader, String layerPaths);
708 private static native void setDebugLayers(String layers);
Cody Northrop0fa1d222018-10-23 13:13:21 -0600709 private static native void setDebugLayersGLES(String layers);
Yiwei Zhang1c51f052019-02-14 12:05:47 -0800710 private static native void setDriverPathAndSphalLibraries(String path, String sphalLibraries);
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800711 private static native void setGpuStats(String driverPackageName, String driverVersionName,
Yiwei Zhangf7b0a5f2019-02-19 16:04:10 -0800712 long driverVersionCode, long driverBuildTime, String appPackageName);
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800713 private static native void setAngleInfo(String path, String appPackage, String devOptIn,
714 FileDescriptor rulesFd, long rulesOffset, long rulesLength);
Tim Van Pattenddc43912018-12-18 17:47:52 -0700715 private static native boolean getShouldUseAngle(String packageName);
Jesse Hall79bf3922016-12-12 12:53:02 -0800716}