blob: 5bf909566f3be24bf74a79e4f019aa100c2dcd2c [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
19import android.content.Context;
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -070020import android.content.Intent;
Jesse Hall79bf3922016-12-12 12:53:02 -080021import android.content.pm.ApplicationInfo;
22import android.content.pm.PackageManager;
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -070023import android.content.pm.ResolveInfo;
Cody Northrop7fd44212018-09-06 10:30:28 -060024import android.content.res.AssetFileDescriptor;
Peiyong Lin88c38eb2018-10-12 15:34:15 -070025import android.content.res.AssetManager;
Peiyong Lin9ca1dd82019-01-12 17:44:29 -080026import android.gamedriver.GameDriverProto.Blacklist;
27import android.gamedriver.GameDriverProto.Blacklists;
Jesse Hallfd104e72017-01-19 17:59:08 -080028import android.opengl.EGL14;
Cody Northrop86cedcb2017-10-20 09:03:13 -060029import android.provider.Settings;
Peiyong Lin9ca1dd82019-01-12 17:44:29 -080030import android.util.Base64;
Jesse Hall79bf3922016-12-12 12:53:02 -080031import android.util.Log;
32
Peiyong Lin9ca1dd82019-01-12 17:44:29 -080033import com.android.framework.protobuf.InvalidProtocolBufferException;
34
Jesse Hall79bf3922016-12-12 12:53:02 -080035import dalvik.system.VMRuntime;
36
Peiyong Lin88c38eb2018-10-12 15:34:15 -070037import java.io.BufferedReader;
Jesse Hall79bf3922016-12-12 12:53:02 -080038import java.io.File;
Cody Northrop7fd44212018-09-06 10:30:28 -060039import java.io.FileDescriptor;
Cody Northrop8d72a6b2018-11-01 08:20:26 -060040import java.io.FileInputStream;
41import java.io.FileNotFoundException;
Peiyong Lin88c38eb2018-10-12 15:34:15 -070042import java.io.IOException;
43import java.io.InputStream;
44import java.io.InputStreamReader;
Tim Van Patten3c612842018-11-09 16:48:24 -070045import java.util.ArrayList;
46import java.util.Arrays;
47import java.util.HashMap;
48import java.util.List;
49import java.util.Map;
Jesse Hall79bf3922016-12-12 12:53:02 -080050
51/** @hide */
Cody Northrop86cedcb2017-10-20 09:03:13 -060052public class GraphicsEnvironment {
53
54 private static final GraphicsEnvironment sInstance = new GraphicsEnvironment();
55
56 /**
57 * Returns the shared {@link GraphicsEnvironment} instance.
58 */
59 public static GraphicsEnvironment getInstance() {
60 return sInstance;
61 }
Jesse Hall79bf3922016-12-12 12:53:02 -080062
63 private static final boolean DEBUG = false;
64 private static final String TAG = "GraphicsEnvironment";
65 private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
Peiyong Lin3a1be742019-01-02 17:46:55 -080066 private static final String GUP_WHITELIST_FILENAME = "whitelist.txt";
Cody Northrop7fd44212018-09-06 10:30:28 -060067 private static final String ANGLE_RULES_FILE = "a4a_rules.json";
Cody Northrop8d72a6b2018-11-01 08:20:26 -060068 private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -070069 private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID";
Peiyong Lin9ca1dd82019-01-12 17:44:29 -080070 private static final String GAME_DRIVER_BLACKLIST_FLAG = "blacklist";
71 private static final int BASE64_FLAGS = Base64.NO_PADDING | Base64.NO_WRAP;
Jesse Hall79bf3922016-12-12 12:53:02 -080072
Cody Northrop86cedcb2017-10-20 09:03:13 -060073 private ClassLoader mClassLoader;
74 private String mLayerPath;
75 private String mDebugLayerPath;
76
77 /**
78 * Set up GraphicsEnvironment
79 */
Cody Northropdeb43282018-10-04 16:04:05 -060080 public void setup(Context context, Bundle coreSettings) {
Cody Northropebe6a562018-10-15 07:22:23 -060081 setupGpuLayers(context, coreSettings);
Tim Van Pattenff9476b2018-12-11 15:41:25 -070082 setupAngle(context, coreSettings, context.getPackageName());
Peiyong Lin2d5a2bb2018-11-07 21:10:07 -080083 chooseDriver(context, coreSettings);
Cody Northrop86cedcb2017-10-20 09:03:13 -060084 }
85
86 /**
87 * Check whether application is debuggable
88 */
89 private static boolean isDebuggable(Context context) {
90 return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) > 0;
91 }
92
93 /**
94 * Store the layer paths available to the loader.
95 */
96 public void setLayerPaths(ClassLoader classLoader,
97 String layerPath,
98 String debugLayerPath) {
99 // We have to store these in the class because they are set up before we
100 // have access to the Context to properly set up GraphicsEnvironment
101 mClassLoader = classLoader;
102 mLayerPath = layerPath;
103 mDebugLayerPath = debugLayerPath;
104 }
105
106 /**
Cody Northropebe6a562018-10-15 07:22:23 -0600107 * Return the debug layer app's on-disk and in-APK lib directories
108 */
109 private static String getDebugLayerAppPaths(Context context, String app) {
110 ApplicationInfo appInfo;
111 try {
112 appInfo = context.getPackageManager().getApplicationInfo(
113 app, PackageManager.MATCH_ALL);
114 } catch (PackageManager.NameNotFoundException e) {
115 Log.w(TAG, "Debug layer app '" + app + "' not installed");
116
117 return null;
118 }
119
120 String abi = chooseAbi(appInfo);
121
122 StringBuilder sb = new StringBuilder();
123 sb.append(appInfo.nativeLibraryDir)
124 .append(File.pathSeparator);
125 sb.append(appInfo.sourceDir)
126 .append("!/lib/")
127 .append(abi);
128 String paths = sb.toString();
129
130 if (DEBUG) Log.v(TAG, "Debug layer app libs: " + paths);
131
132 return paths;
133 }
134
135 /**
Cody Northrop86cedcb2017-10-20 09:03:13 -0600136 * Set up layer search paths for all apps
137 * If debuggable, check for additional debug settings
138 */
Cody Northropebe6a562018-10-15 07:22:23 -0600139 private void setupGpuLayers(Context context, Bundle coreSettings) {
Cody Northrop86cedcb2017-10-20 09:03:13 -0600140
141 String layerPaths = "";
142
143 // Only enable additional debug functionality if the following conditions are met:
Cody Northropebe6a562018-10-15 07:22:23 -0600144 // 1. App is debuggable or device is rooted
Cody Northrop86cedcb2017-10-20 09:03:13 -0600145 // 2. ENABLE_GPU_DEBUG_LAYERS is true
146 // 3. Package name is equal to GPU_DEBUG_APP
147
Cody Northropebe6a562018-10-15 07:22:23 -0600148 if (isDebuggable(context) || (getCanLoadSystemLibraries() == 1)) {
Cody Northrop86cedcb2017-10-20 09:03:13 -0600149
Cody Northropebe6a562018-10-15 07:22:23 -0600150 int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600151
152 if (enable != 0) {
153
Cody Northropebe6a562018-10-15 07:22:23 -0600154 String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600155
156 String packageName = context.getPackageName();
157
158 if ((gpuDebugApp != null && packageName != null)
159 && (!gpuDebugApp.isEmpty() && !packageName.isEmpty())
160 && gpuDebugApp.equals(packageName)) {
161 Log.i(TAG, "GPU debug layers enabled for " + packageName);
162
163 // Prepend the debug layer path as a searchable path.
164 // This will ensure debug layers added will take precedence over
165 // the layers specified by the app.
166 layerPaths = mDebugLayerPath + ":";
167
Cody Northropebe6a562018-10-15 07:22:23 -0600168
169 // If there is a debug layer app specified, add its path.
170 String gpuDebugLayerApp =
171 coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP);
172
173 if (gpuDebugLayerApp != null && !gpuDebugLayerApp.isEmpty()) {
174 Log.i(TAG, "GPU debug layer app: " + gpuDebugLayerApp);
175 String paths = getDebugLayerAppPaths(context, gpuDebugLayerApp);
176 if (paths != null) {
177 // Append the path so files placed in the app's base directory will
178 // override the external path
179 layerPaths += paths + ":";
180 }
181 }
182
183 String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600184
Cody Northrop0fa1d222018-10-23 13:13:21 -0600185 Log.i(TAG, "Vulkan debug layer list: " + layers);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600186 if (layers != null && !layers.isEmpty()) {
187 setDebugLayers(layers);
188 }
Cody Northrop0fa1d222018-10-23 13:13:21 -0600189
190 String layersGLES =
191 coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS_GLES);
192
193 Log.i(TAG, "GLES debug layer list: " + layersGLES);
194 if (layersGLES != null && !layersGLES.isEmpty()) {
195 setDebugLayersGLES(layersGLES);
196 }
Cody Northrop86cedcb2017-10-20 09:03:13 -0600197 }
198 }
Cody Northrop86cedcb2017-10-20 09:03:13 -0600199 }
200
201 // Include the app's lib directory in all cases
202 layerPaths += mLayerPath;
203
204 setLayerPaths(mClassLoader, layerPaths);
205 }
206
Tim Van Patten3c612842018-11-09 16:48:24 -0700207 enum OpenGlDriverChoice {
208 DEFAULT,
209 NATIVE,
210 ANGLE
211 }
212
213 private static final Map<OpenGlDriverChoice, String> sDriverMap = buildMap();
214 private static Map<OpenGlDriverChoice, String> buildMap() {
215 Map<OpenGlDriverChoice, String> map = new HashMap<>();
216 map.put(OpenGlDriverChoice.DEFAULT, "default");
217 map.put(OpenGlDriverChoice.ANGLE, "angle");
218 map.put(OpenGlDriverChoice.NATIVE, "native");
219
220 return map;
221 }
222
223
Tim Van Pattenff9476b2018-12-11 15:41:25 -0700224 private static List<String> getGlobalSettingsString(Bundle bundle, String globalSetting) {
Tim Van Patten3c612842018-11-09 16:48:24 -0700225 List<String> valueList = null;
Tim Van Pattenff9476b2018-12-11 15:41:25 -0700226 String settingsValue = bundle.getString(globalSetting);
Tim Van Patten3c612842018-11-09 16:48:24 -0700227
228 if (settingsValue != null) {
229 valueList = new ArrayList<>(Arrays.asList(settingsValue.split(",")));
230 } else {
231 valueList = new ArrayList<>();
232 }
233
234 return valueList;
235 }
236
237 private static int getGlobalSettingsPkgIndex(String pkgName,
238 List<String> globalSettingsDriverPkgs) {
239 for (int pkgIndex = 0; pkgIndex < globalSettingsDriverPkgs.size(); pkgIndex++) {
240 if (globalSettingsDriverPkgs.get(pkgIndex).equals(pkgName)) {
241 return pkgIndex;
242 }
243 }
244
245 return -1;
246 }
247
Tim Van Pattenff9476b2018-12-11 15:41:25 -0700248 private static String getDriverForPkg(Bundle bundle, String packageName) {
249 String allUseAngle =
250 bundle.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
251 if ((allUseAngle != null) && allUseAngle.equals("1")) {
252 return sDriverMap.get(OpenGlDriverChoice.ANGLE);
Tim Van Patten3c612842018-11-09 16:48:24 -0700253 }
254
255 List<String> globalSettingsDriverPkgs =
Tim Van Pattenff9476b2018-12-11 15:41:25 -0700256 getGlobalSettingsString(bundle,
Tim Van Patten3c612842018-11-09 16:48:24 -0700257 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS);
258 List<String> globalSettingsDriverValues =
Tim Van Pattenff9476b2018-12-11 15:41:25 -0700259 getGlobalSettingsString(bundle,
Tim Van Patten3c612842018-11-09 16:48:24 -0700260 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES);
261
262 // Make sure we have a good package name
263 if ((packageName == null) || (packageName.isEmpty())) {
264 return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
265 }
266 // Make sure we have good settings to use
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700267 if (globalSettingsDriverPkgs.size() != globalSettingsDriverValues.size()) {
Tim Van Patten3c612842018-11-09 16:48:24 -0700268 Log.w(TAG,
269 "Global.Settings values are invalid: "
270 + "globalSettingsDriverPkgs.size = "
271 + globalSettingsDriverPkgs.size() + ", "
272 + "globalSettingsDriverValues.size = "
273 + globalSettingsDriverValues.size());
274 return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
275 }
276
277 int pkgIndex = getGlobalSettingsPkgIndex(packageName, globalSettingsDriverPkgs);
278
279 if (pkgIndex < 0) {
280 return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
281 }
282
283 return globalSettingsDriverValues.get(pkgIndex);
284 }
285
Jesse Hallc37984f2017-05-23 16:55:08 -0700286 /**
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700287 * Get the ANGLE package name.
288 */
289 private String getAnglePackageName(Context context) {
290 Intent intent = new Intent(ACTION_ANGLE_FOR_ANDROID);
291
292 List<ResolveInfo> resolveInfos = context.getPackageManager()
293 .queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
294 if (resolveInfos.size() != 1) {
295 Log.e(TAG, "Invalid number of ANGLE packages. Required: 1, Found: "
296 + resolveInfos.size());
297 for (ResolveInfo resolveInfo : resolveInfos) {
298 Log.e(TAG, "Found ANGLE package: " + resolveInfo.activityInfo.packageName);
299 }
300 return "";
301 }
302
303 // Must be exactly 1 ANGLE PKG found to get here.
304 return resolveInfos.get(0).activityInfo.packageName;
305 }
306
307 /**
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700308 * Attempt to setup ANGLE with a temporary rules file.
309 * True: Temporary rules file was loaded.
310 * False: Temporary rules file was *not* loaded.
311 */
312 private boolean setupAngleWithTempRulesFile(Context context,
313 String packageName,
314 String paths,
315 String devOptIn) {
Tim Van Patten3df66432019-01-14 15:56:12 -0700316 /**
317 * We only want to load a temp rules file for:
318 * - apps that are marked 'debuggable' in their manifest
319 * - devices that are running a userdebug build (ro.debuggable) or can inject libraries for
320 * debugging (PR_SET_DUMPABLE).
321 */
322 boolean appIsDebuggable = isDebuggable(context);
323 boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
324 if (!(appIsDebuggable || deviceIsDebuggable)) {
325 Log.v(TAG, "Skipping loading temporary rules file: "
326 + "appIsDebuggable = " + appIsDebuggable + ", "
327 + "adbRootEnabled = " + deviceIsDebuggable);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700328 return false;
329 }
330
331 String angleTempRules = SystemProperties.get(ANGLE_TEMP_RULES);
332
333 if ((angleTempRules == null) || angleTempRules.isEmpty()) {
334 Log.v(TAG, "System property '" + ANGLE_TEMP_RULES + "' is not set or is empty");
335 return false;
336 }
337
338 Log.i(TAG, "Detected system property " + ANGLE_TEMP_RULES + ": " + angleTempRules);
339
340 File tempRulesFile = new File(angleTempRules);
341 if (tempRulesFile.exists()) {
342 Log.i(TAG, angleTempRules + " exists, loading file.");
343 try {
344 FileInputStream stream = new FileInputStream(angleTempRules);
345
346 try {
347 FileDescriptor rulesFd = stream.getFD();
348 long rulesOffset = 0;
349 long rulesLength = stream.getChannel().size();
350 Log.i(TAG, "Loaded temporary ANGLE rules from " + angleTempRules);
351
352 setAngleInfo(paths, packageName, devOptIn, rulesFd, rulesOffset, rulesLength);
353
354 stream.close();
355
356 // We successfully setup ANGLE, so return with good status
357 return true;
358 } catch (IOException e) {
359 Log.w(TAG, "Hit IOException thrown by FileInputStream: " + e);
360 }
361 } catch (FileNotFoundException e) {
362 Log.w(TAG, "Temp ANGLE rules file not found: " + e);
363 } catch (SecurityException e) {
364 Log.w(TAG, "Temp ANGLE rules file not accessible: " + e);
365 }
366 }
367
368 return false;
369 }
370
371 /**
372 * Attempt to setup ANGLE with a (temporary) default rules file: b/121153494
373 * True: Rules file was loaded.
374 * False: Rules file was *not* loaded.
375 */
376 private boolean setupAngleRulesDebug(String packageName, String paths, String devOptIn) {
377 // b/121153494
378 // Skip APK rules file checking.
379 if (!DEBUG) {
380 Log.v(TAG, "Skipping loading the rules file.");
381 // Fill in some default values for now, so the loader can get an answer when it asks.
382 // Most importantly, we need to indicate which app we are init'ing and what the
383 // developer options for it are so we can turn on ANGLE if needed.
384 setAngleInfo(paths, packageName, devOptIn, null, 0, 0);
385 return true;
386 }
387
388 return false;
389 }
390
391 /**
392 * Attempt to setup ANGLE with a rules file loaded from the ANGLE APK.
393 * True: APK rules file was loaded.
394 * False: APK rules file was *not* loaded.
395 */
396 private boolean setupAngleRulesApk(String anglePkgName,
397 ApplicationInfo angleInfo,
398 Context context,
399 String packageName,
400 String paths,
401 String devOptIn) {
402 // Pass the rules file to loader for ANGLE decisions
403 try {
404 AssetManager angleAssets =
405 context.getPackageManager().getResourcesForApplication(angleInfo).getAssets();
406
407 try {
408 AssetFileDescriptor assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
409
410 setAngleInfo(paths, packageName, devOptIn, assetsFd.getFileDescriptor(),
411 assetsFd.getStartOffset(), assetsFd.getLength());
412
413 assetsFd.close();
414
415 return true;
416 } catch (IOException e) {
417 Log.w(TAG, "Failed to get AssetFileDescriptor for " + ANGLE_RULES_FILE
418 + " from '" + anglePkgName + "': " + e);
419 }
420 } catch (PackageManager.NameNotFoundException e) {
421 Log.w(TAG, "Failed to get AssetManager for '" + anglePkgName + "': " + e);
422 }
423
424 return false;
425 }
426
427 /**
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600428 * Pass ANGLE details down to trigger enable logic
Cody Northrop73c05042018-04-16 13:23:51 -0600429 */
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700430 public void setupAngle(Context context, Bundle bundle, String packageName) {
Tim Van Pattenff9476b2018-12-11 15:41:25 -0700431 String devOptIn = getDriverForPkg(bundle, packageName);
Cody Northrop73c05042018-04-16 13:23:51 -0600432
Tim Van Patten3c612842018-11-09 16:48:24 -0700433 if (DEBUG) {
434 Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
435 + "set to: '" + devOptIn + "'");
Cody Northrop841c3d92018-08-29 16:36:12 -0600436 }
437
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700438 String anglePkgName = getAnglePackageName(context);
439 if (anglePkgName.isEmpty()) {
440 Log.e(TAG, "Failed to find ANGLE package.");
441 return;
442 }
443
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600444 ApplicationInfo angleInfo;
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600445 try {
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700446 angleInfo = context.getPackageManager().getApplicationInfo(anglePkgName,
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600447 PackageManager.MATCH_SYSTEM_ONLY);
448 } catch (PackageManager.NameNotFoundException e) {
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700449 Log.w(TAG, "ANGLE package '" + anglePkgName + "' not installed");
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600450 return;
451 }
452
453 String abi = chooseAbi(angleInfo);
454
455 // Build a path that includes installed native libs and APK
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700456 String paths = angleInfo.nativeLibraryDir
457 + File.pathSeparator
458 + angleInfo.sourceDir
459 + "!/lib/"
460 + abi;
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600461
462 if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
463
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700464 if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) {
465 // We setup ANGLE with a temp rules file, so we're done here.
466 return;
Cody Northrop8d72a6b2018-11-01 08:20:26 -0600467 }
468
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700469 // b/121153494
470 if (setupAngleRulesDebug(packageName, paths, devOptIn)) {
471 // We setup ANGLE with defaults, so we're done here.
472 return;
Cody Northrop7fd44212018-09-06 10:30:28 -0600473 }
474
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700475 if (setupAngleRulesApk(anglePkgName, angleInfo, context, packageName, paths, devOptIn)) {
476 // We setup ANGLE with rules from the APK, so we're done here.
477 return;
478 }
Cody Northrop73c05042018-04-16 13:23:51 -0600479 }
480
481 /**
Jesse Hallc37984f2017-05-23 16:55:08 -0700482 * Choose whether the current process should use the builtin or an updated driver.
Jesse Hallc37984f2017-05-23 16:55:08 -0700483 */
Peiyong Lin2d5a2bb2018-11-07 21:10:07 -0800484 private static void chooseDriver(Context context, Bundle coreSettings) {
Jesse Hall79bf3922016-12-12 12:53:02 -0800485 String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER);
486 if (driverPackageName == null || driverPackageName.isEmpty()) {
487 return;
488 }
Peiyong Lin2d5a2bb2018-11-07 21:10:07 -0800489
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800490 ApplicationInfo driverInfo;
491 try {
492 driverInfo = context.getPackageManager().getApplicationInfo(driverPackageName,
493 PackageManager.MATCH_SYSTEM_ONLY);
494 } catch (PackageManager.NameNotFoundException e) {
495 Log.w(TAG, "driver package '" + driverPackageName + "' not installed");
496 return;
497 }
498
499 // O drivers are restricted to the sphal linker namespace, so don't try to use
500 // packages unless they declare they're compatible with that restriction.
501 if (driverInfo.targetSdkVersion < Build.VERSION_CODES.O) {
502 if (DEBUG) {
503 Log.w(TAG, "updated driver package is not known to be compatible with O");
504 }
505 return;
506 }
507
Jesse Hall79bf3922016-12-12 12:53:02 -0800508 // To minimize risk of driver updates crippling the device beyond user repair, never use an
509 // updated driver for privileged or non-updated system apps. Presumably pre-installed apps
510 // were tested thoroughly with the pre-installed driver.
511 ApplicationInfo ai = context.getApplicationInfo();
512 if (ai.isPrivilegedApp() || (ai.isSystemApp() && !ai.isUpdatedSystemApp())) {
513 if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app");
514 return;
515 }
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700516
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800517 // GUP_DEV_ALL_APPS
518 // 0: Default (Invalid values fallback to default as well)
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800519 // 1: All apps use Game Driver
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800520 // 2: All apps use system graphics driver
521 int gupDevAllApps = coreSettings.getInt(Settings.Global.GUP_DEV_ALL_APPS, 0);
522 if (gupDevAllApps == 2) {
Peiyong Lin2d5a2bb2018-11-07 21:10:07 -0800523 if (DEBUG) {
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800524 Log.w(TAG, "GUP is turned off on this device");
Yiwei Zhang51015a72018-12-29 03:47:56 +0800525 }
526 return;
527 }
528
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800529 if (gupDevAllApps != 1) {
530 // GUP_DEV_OPT_OUT_APPS has higher priority than GUP_DEV_OPT_IN_APPS
531 if (getGlobalSettingsString(coreSettings, Settings.Global.GUP_DEV_OPT_OUT_APPS)
532 .contains(ai.packageName)) {
533 if (DEBUG) {
534 Log.w(TAG, ai.packageName + " opts out from GUP.");
535 }
536 return;
Peiyong Lin2d5a2bb2018-11-07 21:10:07 -0800537 }
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800538 boolean isDevOptIn = getGlobalSettingsString(coreSettings,
539 Settings.Global.GUP_DEV_OPT_IN_APPS)
540 .contains(ai.packageName);
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800541
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800542 if (!isDevOptIn && !onWhitelist(context, driverPackageName, ai.packageName)) {
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800543 if (DEBUG) {
544 Log.w(TAG, ai.packageName + " is not on the whitelist.");
545 }
546 return;
547 }
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700548
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800549 if (!isDevOptIn) {
550 // At this point, the application is on the whitelist only, check whether it's
551 // on the blacklist, terminate early when it's on the blacklist.
552 try {
553 // TODO(b/121350991) Switch to DeviceConfig with property listener.
554 String base64String = coreSettings.getString(Settings.Global.GUP_BLACKLIST);
555 if (base64String != null && !base64String.isEmpty()) {
556 Blacklists blacklistsProto = Blacklists.parseFrom(
557 Base64.decode(base64String, BASE64_FLAGS));
558 List<Blacklist> blacklists = blacklistsProto.getBlacklistsList();
559 long driverVersionCode = driverInfo.longVersionCode;
560 for (Blacklist blacklist : blacklists) {
561 if (blacklist.getVersionCode() == driverVersionCode) {
562 for (String packageName : blacklist.getPackageNamesList()) {
563 if (packageName == ai.packageName) {
564 return;
565 }
566 }
567 break;
568 }
569 }
570 }
571 } catch (InvalidProtocolBufferException e) {
572 if (DEBUG) {
573 Log.w(TAG, "Can't parse blacklist, skip and continue...");
574 }
575 }
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700576 }
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700577 }
578
Jesse Hall79bf3922016-12-12 12:53:02 -0800579 String abi = chooseAbi(driverInfo);
580 if (abi == null) {
581 if (DEBUG) {
582 // This is the normal case for the pre-installed empty driver package, don't spam
583 if (driverInfo.isUpdatedSystemApp()) {
584 Log.w(TAG, "updated driver package has no compatible native libraries");
585 }
586 }
587 return;
588 }
Jesse Hall79bf3922016-12-12 12:53:02 -0800589
590 StringBuilder sb = new StringBuilder();
591 sb.append(driverInfo.nativeLibraryDir)
592 .append(File.pathSeparator);
593 sb.append(driverInfo.sourceDir)
594 .append("!/lib/")
595 .append(abi);
596 String paths = sb.toString();
597
598 if (DEBUG) Log.v(TAG, "gfx driver package libs: " + paths);
599 setDriverPath(paths);
600 }
601
Jesse Hallc37984f2017-05-23 16:55:08 -0700602 /**
603 * Start a background thread to initialize EGL.
604 *
605 * Initializing EGL involves loading and initializing the graphics driver. Some drivers take
606 * several 10s of milliseconds to do this, so doing it on-demand when an app tries to render
607 * its first frame adds directly to user-visible app launch latency. By starting it earlier
608 * on a separate thread, it can usually be finished well before the UI is ready to be drawn.
609 *
610 * Should only be called after chooseDriver().
Jesse Hallc37984f2017-05-23 16:55:08 -0700611 */
612 public static void earlyInitEGL() {
Jesse Hall317fa5a2017-05-23 15:46:55 -0700613 Thread eglInitThread = new Thread(
614 () -> {
615 EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);
616 },
617 "EGL Init");
618 eglInitThread.start();
619 }
620
Jesse Hall79bf3922016-12-12 12:53:02 -0800621 private static String chooseAbi(ApplicationInfo ai) {
622 String isa = VMRuntime.getCurrentInstructionSet();
623 if (ai.primaryCpuAbi != null &&
624 isa.equals(VMRuntime.getInstructionSet(ai.primaryCpuAbi))) {
625 return ai.primaryCpuAbi;
626 }
627 if (ai.secondaryCpuAbi != null &&
628 isa.equals(VMRuntime.getInstructionSet(ai.secondaryCpuAbi))) {
629 return ai.secondaryCpuAbi;
630 }
631 return null;
632 }
633
Peiyong Lin2d5a2bb2018-11-07 21:10:07 -0800634 private static boolean onWhitelist(Context context, String driverPackageName,
635 String applicationPackageName) {
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700636 try {
637 Context driverContext = context.createPackageContext(driverPackageName,
638 Context.CONTEXT_RESTRICTED);
639 AssetManager assets = driverContext.getAssets();
Peiyong Lin3a1be742019-01-02 17:46:55 -0800640 InputStream stream = assets.open(GUP_WHITELIST_FILENAME);
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700641 BufferedReader reader = new BufferedReader(new InputStreamReader(stream));
Peiyong Lin2d5a2bb2018-11-07 21:10:07 -0800642 for (String packageName; (packageName = reader.readLine()) != null; ) {
643 if (packageName.equals(applicationPackageName)) {
644 return true;
645 }
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700646 }
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700647 } catch (PackageManager.NameNotFoundException e) {
648 if (DEBUG) {
649 Log.w(TAG, "driver package '" + driverPackageName + "' not installed");
650 }
651 } catch (IOException e) {
652 if (DEBUG) {
653 Log.w(TAG, "Failed to load whitelist driver package, abort.");
654 }
655 }
Peiyong Lin2d5a2bb2018-11-07 21:10:07 -0800656 return false;
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700657 }
658
Cody Northropebe6a562018-10-15 07:22:23 -0600659 private static native int getCanLoadSystemLibraries();
Cody Northrop86cedcb2017-10-20 09:03:13 -0600660 private static native void setLayerPaths(ClassLoader classLoader, String layerPaths);
661 private static native void setDebugLayers(String layers);
Cody Northrop0fa1d222018-10-23 13:13:21 -0600662 private static native void setDebugLayersGLES(String layers);
Jesse Hall79bf3922016-12-12 12:53:02 -0800663 private static native void setDriverPath(String path);
Cody Northrop6d8d9682018-10-29 10:59:49 -0600664 private static native void setAngleInfo(String path, String appPackage,
Tim Van Patten3c612842018-11-09 16:48:24 -0700665 String devOptIn, FileDescriptor rulesFd,
Cody Northrop7fd44212018-09-06 10:30:28 -0600666 long rulesOffset, long rulesLength);
Jesse Hall79bf3922016-12-12 12:53:02 -0800667}