blob: 39e91383c6a4baf0778d9ada66669b14ed9fbbd3 [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 Pattenb225b442019-03-07 09:35:26 -070019import android.app.Activity;
20import android.content.BroadcastReceiver;
Tim Van Pattenddc43912018-12-18 17:47:52 -070021import android.content.ContentResolver;
Jesse Hall79bf3922016-12-12 12:53:02 -080022import android.content.Context;
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -070023import android.content.Intent;
Jesse Hall79bf3922016-12-12 12:53:02 -080024import android.content.pm.ApplicationInfo;
Yiwei Zhang33097bf2019-02-04 19:01:21 -080025import android.content.pm.PackageInfo;
Jesse Hall79bf3922016-12-12 12:53:02 -080026import android.content.pm.PackageManager;
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -070027import android.content.pm.ResolveInfo;
Cody Northrop7fd44212018-09-06 10:30:28 -060028import android.content.res.AssetFileDescriptor;
Peiyong Lin88c38eb2018-10-12 15:34:15 -070029import android.content.res.AssetManager;
Cody Northrop86cedcb2017-10-20 09:03:13 -060030import android.provider.Settings;
Jesse Hall79bf3922016-12-12 12:53:02 -080031import android.util.Log;
Tim Van Pattenddc43912018-12-18 17:47:52 -070032import android.widget.Toast;
Jesse Hall79bf3922016-12-12 12:53:02 -080033
34import dalvik.system.VMRuntime;
35
36import java.io.File;
Cody Northrop7fd44212018-09-06 10:30:28 -060037import java.io.FileDescriptor;
Cody Northrop8d72a6b2018-11-01 08:20:26 -060038import java.io.FileInputStream;
39import java.io.FileNotFoundException;
Peiyong Lin88c38eb2018-10-12 15:34:15 -070040import java.io.IOException;
Tim Van Patten3c612842018-11-09 16:48:24 -070041import java.util.ArrayList;
42import java.util.Arrays;
43import java.util.HashMap;
44import java.util.List;
45import java.util.Map;
Jesse Hall79bf3922016-12-12 12:53:02 -080046
47/** @hide */
Cody Northrop86cedcb2017-10-20 09:03:13 -060048public class GraphicsEnvironment {
49
50 private static final GraphicsEnvironment sInstance = new GraphicsEnvironment();
51
52 /**
53 * Returns the shared {@link GraphicsEnvironment} instance.
54 */
55 public static GraphicsEnvironment getInstance() {
56 return sInstance;
57 }
Jesse Hall79bf3922016-12-12 12:53:02 -080058
59 private static final boolean DEBUG = false;
60 private static final String TAG = "GraphicsEnvironment";
Yiwei Zhang33097bf2019-02-04 19:01:21 -080061 private static final String SYSTEM_DRIVER_NAME = "system";
62 private static final String SYSTEM_DRIVER_VERSION_NAME = "";
63 private static final long SYSTEM_DRIVER_VERSION_CODE = 0;
Jesse Hall79bf3922016-12-12 12:53:02 -080064 private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
Yiwei Zhangf7b0a5f2019-02-19 16:04:10 -080065 private static final String PROPERTY_GFX_DRIVER_BUILD_TIME = "ro.gfx.driver_build_time";
66 private static final String METADATA_DRIVER_BUILD_TIME = "driver_build_time";
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";
Tim Van Pattenb225b442019-03-07 09:35:26 -070070 private static final String ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE =
71 "android.app.action.ANGLE_FOR_ANDROID_TOAST_MESSAGE";
72 private static final String INTENT_KEY_A4A_TOAST_MESSAGE = "A4A Toast Message";
Peiyong Linb76bfe92019-02-13 14:46:54 -080073 private static final String GAME_DRIVER_WHITELIST_ALL = "*";
Jesse Hall79bf3922016-12-12 12:53:02 -080074
Cody Northrop86cedcb2017-10-20 09:03:13 -060075 private ClassLoader mClassLoader;
76 private String mLayerPath;
77 private String mDebugLayerPath;
78
79 /**
80 * Set up GraphicsEnvironment
81 */
Cody Northropdeb43282018-10-04 16:04:05 -060082 public void setup(Context context, Bundle coreSettings) {
Yiwei Zhang33097bf2019-02-04 19:01:21 -080083 final PackageManager pm = context.getPackageManager();
84 final String packageName = context.getPackageName();
85 setupGpuLayers(context, coreSettings, pm, packageName);
86 setupAngle(context, coreSettings, pm, packageName);
87 if (!chooseDriver(context, coreSettings, pm, packageName)) {
88 setGpuStats(SYSTEM_DRIVER_NAME, SYSTEM_DRIVER_VERSION_NAME, SYSTEM_DRIVER_VERSION_CODE,
Yiwei Zhangf7b0a5f2019-02-19 16:04:10 -080089 SystemProperties.getLong(PROPERTY_GFX_DRIVER_BUILD_TIME, 0), packageName);
Yiwei Zhang33097bf2019-02-04 19:01:21 -080090 }
Cody Northrop86cedcb2017-10-20 09:03:13 -060091 }
92
93 /**
94 * Check whether application is debuggable
95 */
96 private static boolean isDebuggable(Context context) {
97 return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) > 0;
98 }
99
100 /**
101 * Store the layer paths available to the loader.
102 */
103 public void setLayerPaths(ClassLoader classLoader,
104 String layerPath,
105 String debugLayerPath) {
106 // We have to store these in the class because they are set up before we
107 // have access to the Context to properly set up GraphicsEnvironment
108 mClassLoader = classLoader;
109 mLayerPath = layerPath;
110 mDebugLayerPath = debugLayerPath;
111 }
112
113 /**
Cody Northropebe6a562018-10-15 07:22:23 -0600114 * Return the debug layer app's on-disk and in-APK lib directories
115 */
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800116 private static String getDebugLayerAppPaths(PackageManager pm, String app) {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800117 final ApplicationInfo appInfo;
Cody Northropebe6a562018-10-15 07:22:23 -0600118 try {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800119 appInfo = pm.getApplicationInfo(app, PackageManager.MATCH_ALL);
Cody Northropebe6a562018-10-15 07:22:23 -0600120 } catch (PackageManager.NameNotFoundException e) {
121 Log.w(TAG, "Debug layer app '" + app + "' not installed");
122
123 return null;
124 }
125
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800126 final String abi = chooseAbi(appInfo);
Cody Northropebe6a562018-10-15 07:22:23 -0600127
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800128 final StringBuilder sb = new StringBuilder();
Cody Northropebe6a562018-10-15 07:22:23 -0600129 sb.append(appInfo.nativeLibraryDir)
130 .append(File.pathSeparator);
131 sb.append(appInfo.sourceDir)
132 .append("!/lib/")
133 .append(abi);
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800134 final String paths = sb.toString();
Cody Northropebe6a562018-10-15 07:22:23 -0600135
136 if (DEBUG) Log.v(TAG, "Debug layer app libs: " + paths);
137
138 return paths;
139 }
140
141 /**
Cody Northrop86cedcb2017-10-20 09:03:13 -0600142 * Set up layer search paths for all apps
143 * If debuggable, check for additional debug settings
144 */
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800145 private void setupGpuLayers(
146 Context context, Bundle coreSettings, PackageManager pm, String packageName) {
Cody Northrop86cedcb2017-10-20 09:03:13 -0600147 String layerPaths = "";
148
149 // Only enable additional debug functionality if the following conditions are met:
Cody Northropebe6a562018-10-15 07:22:23 -0600150 // 1. App is debuggable or device is rooted
Cody Northrop86cedcb2017-10-20 09:03:13 -0600151 // 2. ENABLE_GPU_DEBUG_LAYERS is true
152 // 3. Package name is equal to GPU_DEBUG_APP
153
Cody Northropebe6a562018-10-15 07:22:23 -0600154 if (isDebuggable(context) || (getCanLoadSystemLibraries() == 1)) {
Cody Northrop86cedcb2017-10-20 09:03:13 -0600155
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800156 final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600157
158 if (enable != 0) {
159
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800160 final String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600161
Cody Northrop86cedcb2017-10-20 09:03:13 -0600162 if ((gpuDebugApp != null && packageName != null)
163 && (!gpuDebugApp.isEmpty() && !packageName.isEmpty())
164 && gpuDebugApp.equals(packageName)) {
165 Log.i(TAG, "GPU debug layers enabled for " + packageName);
166
167 // Prepend the debug layer path as a searchable path.
168 // This will ensure debug layers added will take precedence over
169 // the layers specified by the app.
170 layerPaths = mDebugLayerPath + ":";
171
Cody Northropebe6a562018-10-15 07:22:23 -0600172 // If there is a debug layer app specified, add its path.
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800173 final String gpuDebugLayerApp =
Cody Northropebe6a562018-10-15 07:22:23 -0600174 coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP);
175
176 if (gpuDebugLayerApp != null && !gpuDebugLayerApp.isEmpty()) {
177 Log.i(TAG, "GPU debug layer app: " + gpuDebugLayerApp);
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800178 final String paths = getDebugLayerAppPaths(pm, gpuDebugLayerApp);
Cody Northropebe6a562018-10-15 07:22:23 -0600179 if (paths != null) {
180 // Append the path so files placed in the app's base directory will
181 // override the external path
182 layerPaths += paths + ":";
183 }
184 }
185
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800186 final String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600187
Cody Northrop0fa1d222018-10-23 13:13:21 -0600188 Log.i(TAG, "Vulkan debug layer list: " + layers);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600189 if (layers != null && !layers.isEmpty()) {
190 setDebugLayers(layers);
191 }
Cody Northrop0fa1d222018-10-23 13:13:21 -0600192
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800193 final String layersGLES =
Cody Northrop0fa1d222018-10-23 13:13:21 -0600194 coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS_GLES);
195
196 Log.i(TAG, "GLES debug layer list: " + layersGLES);
197 if (layersGLES != null && !layersGLES.isEmpty()) {
198 setDebugLayersGLES(layersGLES);
199 }
Cody Northrop86cedcb2017-10-20 09:03:13 -0600200 }
201 }
Cody Northrop86cedcb2017-10-20 09:03:13 -0600202 }
203
204 // Include the app's lib directory in all cases
205 layerPaths += mLayerPath;
206
207 setLayerPaths(mClassLoader, layerPaths);
208 }
209
Tim Van Patten3c612842018-11-09 16:48:24 -0700210 enum OpenGlDriverChoice {
211 DEFAULT,
212 NATIVE,
213 ANGLE
214 }
215
216 private static final Map<OpenGlDriverChoice, String> sDriverMap = buildMap();
217 private static Map<OpenGlDriverChoice, String> buildMap() {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800218 final Map<OpenGlDriverChoice, String> map = new HashMap<>();
Tim Van Patten3c612842018-11-09 16:48:24 -0700219 map.put(OpenGlDriverChoice.DEFAULT, "default");
220 map.put(OpenGlDriverChoice.ANGLE, "angle");
221 map.put(OpenGlDriverChoice.NATIVE, "native");
222
223 return map;
224 }
225
226
Tim Van Pattenddc43912018-12-18 17:47:52 -0700227 private static List<String> getGlobalSettingsString(ContentResolver contentResolver,
228 Bundle bundle,
229 String globalSetting) {
230 final List<String> valueList;
231 final String settingsValue;
232
233 if (bundle != null) {
234 settingsValue = bundle.getString(globalSetting);
235 } else {
236 settingsValue = Settings.Global.getString(contentResolver, globalSetting);
237 }
Tim Van Patten3c612842018-11-09 16:48:24 -0700238
239 if (settingsValue != null) {
240 valueList = new ArrayList<>(Arrays.asList(settingsValue.split(",")));
241 } else {
242 valueList = new ArrayList<>();
243 }
244
245 return valueList;
246 }
247
248 private static int getGlobalSettingsPkgIndex(String pkgName,
249 List<String> globalSettingsDriverPkgs) {
250 for (int pkgIndex = 0; pkgIndex < globalSettingsDriverPkgs.size(); pkgIndex++) {
251 if (globalSettingsDriverPkgs.get(pkgIndex).equals(pkgName)) {
252 return pkgIndex;
253 }
254 }
255
256 return -1;
257 }
258
Tim Van Pattenddc43912018-12-18 17:47:52 -0700259 private static String getDriverForPkg(Context context, Bundle bundle, String packageName) {
260 final String allUseAngle;
261 if (bundle != null) {
262 allUseAngle =
263 bundle.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
264 } else {
265 ContentResolver contentResolver = context.getContentResolver();
266 allUseAngle = Settings.Global.getString(contentResolver,
267 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
268 }
Tim Van Pattenff9476b2018-12-11 15:41:25 -0700269 if ((allUseAngle != null) && allUseAngle.equals("1")) {
270 return sDriverMap.get(OpenGlDriverChoice.ANGLE);
Tim Van Patten3c612842018-11-09 16:48:24 -0700271 }
272
Tim Van Pattenddc43912018-12-18 17:47:52 -0700273 final ContentResolver contentResolver = context.getContentResolver();
274 final List<String> globalSettingsDriverPkgs =
275 getGlobalSettingsString(contentResolver, bundle,
276 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS);
277 final List<String> globalSettingsDriverValues =
278 getGlobalSettingsString(contentResolver, bundle,
279 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES);
Tim Van Patten3c612842018-11-09 16:48:24 -0700280
281 // Make sure we have a good package name
282 if ((packageName == null) || (packageName.isEmpty())) {
283 return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
284 }
285 // Make sure we have good settings to use
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700286 if (globalSettingsDriverPkgs.size() != globalSettingsDriverValues.size()) {
Tim Van Patten3c612842018-11-09 16:48:24 -0700287 Log.w(TAG,
288 "Global.Settings values are invalid: "
289 + "globalSettingsDriverPkgs.size = "
290 + globalSettingsDriverPkgs.size() + ", "
291 + "globalSettingsDriverValues.size = "
292 + globalSettingsDriverValues.size());
293 return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
294 }
295
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800296 final int pkgIndex = getGlobalSettingsPkgIndex(packageName, globalSettingsDriverPkgs);
Tim Van Patten3c612842018-11-09 16:48:24 -0700297
298 if (pkgIndex < 0) {
299 return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
300 }
301
302 return globalSettingsDriverValues.get(pkgIndex);
303 }
304
Jesse Hallc37984f2017-05-23 16:55:08 -0700305 /**
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700306 * Get the ANGLE package name.
307 */
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800308 private String getAnglePackageName(PackageManager pm) {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800309 final Intent intent = new Intent(ACTION_ANGLE_FOR_ANDROID);
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700310
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800311 final List<ResolveInfo> resolveInfos =
312 pm.queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700313 if (resolveInfos.size() != 1) {
314 Log.e(TAG, "Invalid number of ANGLE packages. Required: 1, Found: "
315 + resolveInfos.size());
316 for (ResolveInfo resolveInfo : resolveInfos) {
317 Log.e(TAG, "Found ANGLE package: " + resolveInfo.activityInfo.packageName);
318 }
319 return "";
320 }
321
322 // Must be exactly 1 ANGLE PKG found to get here.
323 return resolveInfos.get(0).activityInfo.packageName;
324 }
325
326 /**
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700327 * Attempt to setup ANGLE with a temporary rules file.
328 * True: Temporary rules file was loaded.
329 * False: Temporary rules file was *not* loaded.
330 */
Tim Van Pattenddc43912018-12-18 17:47:52 -0700331 private static boolean setupAngleWithTempRulesFile(Context context,
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700332 String packageName,
333 String paths,
334 String devOptIn) {
Tim Van Patten3df66432019-01-14 15:56:12 -0700335 /**
336 * We only want to load a temp rules file for:
337 * - apps that are marked 'debuggable' in their manifest
338 * - devices that are running a userdebug build (ro.debuggable) or can inject libraries for
339 * debugging (PR_SET_DUMPABLE).
340 */
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800341 final boolean appIsDebuggable = isDebuggable(context);
342 final boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
Tim Van Patten3df66432019-01-14 15:56:12 -0700343 if (!(appIsDebuggable || deviceIsDebuggable)) {
344 Log.v(TAG, "Skipping loading temporary rules file: "
345 + "appIsDebuggable = " + appIsDebuggable + ", "
346 + "adbRootEnabled = " + deviceIsDebuggable);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700347 return false;
348 }
349
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800350 final String angleTempRules = SystemProperties.get(ANGLE_TEMP_RULES);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700351
352 if ((angleTempRules == null) || angleTempRules.isEmpty()) {
353 Log.v(TAG, "System property '" + ANGLE_TEMP_RULES + "' is not set or is empty");
354 return false;
355 }
356
357 Log.i(TAG, "Detected system property " + ANGLE_TEMP_RULES + ": " + angleTempRules);
358
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800359 final File tempRulesFile = new File(angleTempRules);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700360 if (tempRulesFile.exists()) {
361 Log.i(TAG, angleTempRules + " exists, loading file.");
362 try {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800363 final FileInputStream stream = new FileInputStream(angleTempRules);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700364
365 try {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800366 final FileDescriptor rulesFd = stream.getFD();
367 final long rulesOffset = 0;
368 final long rulesLength = stream.getChannel().size();
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700369 Log.i(TAG, "Loaded temporary ANGLE rules from " + angleTempRules);
370
371 setAngleInfo(paths, packageName, devOptIn, rulesFd, rulesOffset, rulesLength);
372
373 stream.close();
374
375 // We successfully setup ANGLE, so return with good status
376 return true;
377 } catch (IOException e) {
378 Log.w(TAG, "Hit IOException thrown by FileInputStream: " + e);
379 }
380 } catch (FileNotFoundException e) {
381 Log.w(TAG, "Temp ANGLE rules file not found: " + e);
382 } catch (SecurityException e) {
383 Log.w(TAG, "Temp ANGLE rules file not accessible: " + e);
384 }
385 }
386
387 return false;
388 }
389
390 /**
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700391 * Attempt to setup ANGLE with a rules file loaded from the ANGLE APK.
392 * True: APK rules file was loaded.
393 * False: APK rules file was *not* loaded.
394 */
Tim Van Pattenddc43912018-12-18 17:47:52 -0700395 private static boolean setupAngleRulesApk(String anglePkgName,
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700396 ApplicationInfo angleInfo,
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800397 PackageManager pm,
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700398 String packageName,
399 String paths,
400 String devOptIn) {
401 // Pass the rules file to loader for ANGLE decisions
402 try {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800403 final AssetManager angleAssets = pm.getResourcesForApplication(angleInfo).getAssets();
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700404
405 try {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800406 final AssetFileDescriptor assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700407
408 setAngleInfo(paths, packageName, devOptIn, assetsFd.getFileDescriptor(),
409 assetsFd.getStartOffset(), assetsFd.getLength());
410
411 assetsFd.close();
412
413 return true;
414 } catch (IOException e) {
415 Log.w(TAG, "Failed to get AssetFileDescriptor for " + ANGLE_RULES_FILE
416 + " from '" + anglePkgName + "': " + e);
417 }
418 } catch (PackageManager.NameNotFoundException e) {
419 Log.w(TAG, "Failed to get AssetManager for '" + anglePkgName + "': " + e);
420 }
421
422 return false;
423 }
424
425 /**
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700426 * Pull ANGLE whitelist from GlobalSettings and compare against current package
427 */
Tim Van Pattenddc43912018-12-18 17:47:52 -0700428 private static boolean checkAngleWhitelist(Context context, Bundle bundle, String packageName) {
429 final ContentResolver contentResolver = context.getContentResolver();
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800430 final List<String> angleWhitelist =
Tim Van Pattenddc43912018-12-18 17:47:52 -0700431 getGlobalSettingsString(contentResolver, bundle,
432 Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST);
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700433
434 return angleWhitelist.contains(packageName);
435 }
436
437 /**
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600438 * Pass ANGLE details down to trigger enable logic
Tim Van Pattenddc43912018-12-18 17:47:52 -0700439 *
440 * @param context
441 * @param bundle
442 * @param packageName
443 * @return true: ANGLE setup successfully
444 * false: ANGLE not setup (not on whitelist, ANGLE not present, etc.)
Cody Northrop73c05042018-04-16 13:23:51 -0600445 */
Tim Van Pattenddc43912018-12-18 17:47:52 -0700446 public boolean setupAngle(Context context, Bundle bundle, PackageManager pm,
447 String packageName) {
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700448 if (packageName.isEmpty()) {
449 Log.v(TAG, "No package name available yet, skipping ANGLE setup");
Tim Van Pattenddc43912018-12-18 17:47:52 -0700450 return false;
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700451 }
Cody Northrop73c05042018-04-16 13:23:51 -0600452
Tim Van Pattenddc43912018-12-18 17:47:52 -0700453 final String devOptIn = getDriverForPkg(context, bundle, packageName);
Tim Van Patten3c612842018-11-09 16:48:24 -0700454 if (DEBUG) {
455 Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
456 + "set to: '" + devOptIn + "'");
Cody Northrop841c3d92018-08-29 16:36:12 -0600457 }
458
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700459 // We only need to check rules if the app is whitelisted or the developer has
460 // explicitly chosen something other than default driver.
461 //
462 // The whitelist will be generated by the ANGLE APK at both boot time and
463 // ANGLE update time. It will only include apps mentioned in the rules file.
464 //
465 // If the user has set the developer option to something other than default,
466 // we need to call setupAngleRulesApk() with the package name and the developer
467 // option value (native/angle/other). Then later when we are actually trying to
468 // load a driver, GraphicsEnv::shouldUseAngle() has seen the package name before
469 // and can confidently answer yes/no based on the previously set developer
470 // option value.
Tim Van Pattenddc43912018-12-18 17:47:52 -0700471 final boolean whitelisted = checkAngleWhitelist(context, bundle, packageName);
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800472 final boolean defaulted = devOptIn.equals(sDriverMap.get(OpenGlDriverChoice.DEFAULT));
473 final boolean rulesCheck = (whitelisted || !defaulted);
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700474 if (!rulesCheck) {
Tim Van Pattenddc43912018-12-18 17:47:52 -0700475 return false;
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700476 }
477
478 if (whitelisted) {
479 Log.v(TAG, "ANGLE whitelist includes " + packageName);
480 }
481 if (!defaulted) {
482 Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
483 }
484
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800485 final String anglePkgName = getAnglePackageName(pm);
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700486 if (anglePkgName.isEmpty()) {
487 Log.e(TAG, "Failed to find ANGLE package.");
Tim Van Pattenddc43912018-12-18 17:47:52 -0700488 return false;
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700489 }
490
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800491 final ApplicationInfo angleInfo;
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600492 try {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800493 angleInfo = pm.getApplicationInfo(anglePkgName, PackageManager.MATCH_SYSTEM_ONLY);
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600494 } catch (PackageManager.NameNotFoundException e) {
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700495 Log.w(TAG, "ANGLE package '" + anglePkgName + "' not installed");
Tim Van Pattenddc43912018-12-18 17:47:52 -0700496 return false;
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600497 }
498
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800499 final String abi = chooseAbi(angleInfo);
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600500
501 // Build a path that includes installed native libs and APK
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800502 final String paths = angleInfo.nativeLibraryDir
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700503 + File.pathSeparator
504 + angleInfo.sourceDir
505 + "!/lib/"
506 + abi;
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600507
508 if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
509
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700510 if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) {
511 // We setup ANGLE with a temp rules file, so we're done here.
Tim Van Pattenddc43912018-12-18 17:47:52 -0700512 return true;
Cody Northrop8d72a6b2018-11-01 08:20:26 -0600513 }
514
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800515 if (setupAngleRulesApk(anglePkgName, angleInfo, pm, packageName, paths, devOptIn)) {
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700516 // We setup ANGLE with rules from the APK, so we're done here.
Tim Van Pattenddc43912018-12-18 17:47:52 -0700517 return true;
518 }
519
520 return false;
521 }
522
523 /**
524 * Determine if the "ANGLE In Use" dialog box should be shown.
525 */
526 private boolean shouldShowAngleInUseDialogBox(Context context) {
527 try {
528 ContentResolver contentResolver = context.getContentResolver();
529 final int showDialogBox = Settings.Global.getInt(contentResolver,
530 Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX);
531
532 return (showDialogBox == 1);
533 } catch (Settings.SettingNotFoundException | SecurityException e) {
534 // Do nothing and move on
535 }
536
537 // No setting, so assume false
538 return false;
539 }
540
541 /**
542 * Determine if ANGLE should be used.
543 */
544 private boolean shouldUseAngle(Context context, String packageName) {
545 // Need to make sure we are evaluating ANGLE usage for the correct circumstances
546 if (!setupAngle(context, null, context.getPackageManager(), packageName)) {
547 Log.v(TAG, "Package '" + packageName + "' should use not ANGLE");
548 return false;
549 }
550
551 final boolean useAngle = getShouldUseAngle(packageName);
552 Log.v(TAG, "Package '" + packageName + "' should use ANGLE = '" + useAngle + "'");
553
554 return useAngle;
555 }
556
557 /**
558 * Show the ANGLE in Use Dialog Box
559 * @param context
560 */
561 public void showAngleInUseDialogBox(Context context) {
562 final String packageName = context.getPackageName();
563
564 if (shouldShowAngleInUseDialogBox(context) && shouldUseAngle(context, packageName)) {
Tim Van Pattenb225b442019-03-07 09:35:26 -0700565 final Intent intent = new Intent(ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE);
566 String anglePkg = getAnglePackageName(context.getPackageManager());
567 intent.setPackage(anglePkg);
568
569 context.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
570 @Override
571 public void onReceive(Context context, Intent intent) {
572 Bundle results = getResultExtras(true);
573
574 String toastMsg = results.getString(INTENT_KEY_A4A_TOAST_MESSAGE);
575 final Toast toast = Toast.makeText(context, toastMsg, Toast.LENGTH_LONG);
576 toast.show();
577 }
578 }, null, Activity.RESULT_OK, null, null);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700579 }
Cody Northrop73c05042018-04-16 13:23:51 -0600580 }
581
582 /**
Jesse Hallc37984f2017-05-23 16:55:08 -0700583 * Choose whether the current process should use the builtin or an updated driver.
Jesse Hallc37984f2017-05-23 16:55:08 -0700584 */
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800585 private static boolean chooseDriver(
586 Context context, Bundle coreSettings, PackageManager pm, String packageName) {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800587 final String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER);
Jesse Hall79bf3922016-12-12 12:53:02 -0800588 if (driverPackageName == null || driverPackageName.isEmpty()) {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800589 return false;
Jesse Hall79bf3922016-12-12 12:53:02 -0800590 }
Peiyong Lin2d5a2bb2018-11-07 21:10:07 -0800591
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800592 final PackageInfo driverPackageInfo;
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800593 try {
Yiwei Zhang31f5adb2019-02-15 16:15:17 -0800594 driverPackageInfo = pm.getPackageInfo(driverPackageName,
595 PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA);
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800596 } catch (PackageManager.NameNotFoundException e) {
597 Log.w(TAG, "driver package '" + driverPackageName + "' not installed");
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800598 return false;
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800599 }
600
601 // O drivers are restricted to the sphal linker namespace, so don't try to use
602 // packages unless they declare they're compatible with that restriction.
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800603 final ApplicationInfo driverAppInfo = driverPackageInfo.applicationInfo;
604 if (driverAppInfo.targetSdkVersion < Build.VERSION_CODES.O) {
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800605 if (DEBUG) {
606 Log.w(TAG, "updated driver package is not known to be compatible with O");
607 }
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800608 return false;
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800609 }
610
Jesse Hall79bf3922016-12-12 12:53:02 -0800611 // To minimize risk of driver updates crippling the device beyond user repair, never use an
612 // updated driver for privileged or non-updated system apps. Presumably pre-installed apps
613 // were tested thoroughly with the pre-installed driver.
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800614 final ApplicationInfo ai = context.getApplicationInfo();
Jesse Hall79bf3922016-12-12 12:53:02 -0800615 if (ai.isPrivilegedApp() || (ai.isSystemApp() && !ai.isUpdatedSystemApp())) {
616 if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app");
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800617 return false;
Jesse Hall79bf3922016-12-12 12:53:02 -0800618 }
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700619
Yiwei Zhang2b3be862019-01-24 14:45:53 -0800620 // GAME_DRIVER_ALL_APPS
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800621 // 0: Default (Invalid values fallback to default as well)
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800622 // 1: All apps use Game Driver
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800623 // 2: All apps use system graphics driver
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800624 final int gameDriverAllApps = coreSettings.getInt(Settings.Global.GAME_DRIVER_ALL_APPS, 0);
Yiwei Zhang2b3be862019-01-24 14:45:53 -0800625 if (gameDriverAllApps == 2) {
Peiyong Lin2d5a2bb2018-11-07 21:10:07 -0800626 if (DEBUG) {
Yiwei Zhang2b3be862019-01-24 14:45:53 -0800627 Log.w(TAG, "Game Driver is turned off on this device");
Yiwei Zhang51015a72018-12-29 03:47:56 +0800628 }
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800629 return false;
Yiwei Zhang51015a72018-12-29 03:47:56 +0800630 }
631
Yiwei Zhang2b3be862019-01-24 14:45:53 -0800632 if (gameDriverAllApps != 1) {
633 // GAME_DRIVER_OPT_OUT_APPS has higher priority than GAME_DRIVER_OPT_IN_APPS
Tim Van Pattenddc43912018-12-18 17:47:52 -0700634 if (getGlobalSettingsString(null, coreSettings,
635 Settings.Global.GAME_DRIVER_OPT_OUT_APPS).contains(packageName)) {
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800636 if (DEBUG) {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800637 Log.w(TAG, packageName + " opts out from Game Driver.");
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800638 }
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800639 return false;
Peiyong Lin2d5a2bb2018-11-07 21:10:07 -0800640 }
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800641 final boolean isOptIn =
Tim Van Pattenddc43912018-12-18 17:47:52 -0700642 getGlobalSettingsString(null, coreSettings,
643 Settings.Global.GAME_DRIVER_OPT_IN_APPS).contains(packageName);
Peiyong Linb76bfe92019-02-13 14:46:54 -0800644 final List<String> whitelist = getGlobalSettingsString(null, coreSettings,
645 Settings.Global.GAME_DRIVER_WHITELIST);
646 if (!isOptIn && whitelist.indexOf(GAME_DRIVER_WHITELIST_ALL) != 0
647 && !whitelist.contains(packageName)) {
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800648 if (DEBUG) {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800649 Log.w(TAG, packageName + " is not on the whitelist.");
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800650 }
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800651 return false;
Yiwei Zhang4a626ac2019-01-10 10:23:09 +0800652 }
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700653
Peiyong Lin24854202019-02-13 20:02:33 +0000654 // If the application is not opted-in and check whether it's on the blacklist,
655 // terminate early if it's on the blacklist and fallback to system driver.
656 if (!isOptIn
657 && getGlobalSettingsString(null, coreSettings,
658 Settings.Global.GAME_DRIVER_BLACKLIST)
659 .contains(ai.packageName)) {
660 return false;
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700661 }
Peiyong Lin88c38eb2018-10-12 15:34:15 -0700662 }
663
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800664 final String abi = chooseAbi(driverAppInfo);
Jesse Hall79bf3922016-12-12 12:53:02 -0800665 if (abi == null) {
666 if (DEBUG) {
667 // This is the normal case for the pre-installed empty driver package, don't spam
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800668 if (driverAppInfo.isUpdatedSystemApp()) {
Jesse Hall79bf3922016-12-12 12:53:02 -0800669 Log.w(TAG, "updated driver package has no compatible native libraries");
670 }
671 }
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800672 return false;
Jesse Hall79bf3922016-12-12 12:53:02 -0800673 }
Jesse Hall79bf3922016-12-12 12:53:02 -0800674
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800675 final StringBuilder sb = new StringBuilder();
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800676 sb.append(driverAppInfo.nativeLibraryDir)
Jesse Hall79bf3922016-12-12 12:53:02 -0800677 .append(File.pathSeparator);
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800678 sb.append(driverAppInfo.sourceDir)
Jesse Hall79bf3922016-12-12 12:53:02 -0800679 .append("!/lib/")
680 .append(abi);
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800681 final String paths = sb.toString();
Jesse Hall79bf3922016-12-12 12:53:02 -0800682
Yiwei Zhang1c51f052019-02-14 12:05:47 -0800683 final String sphalLibraries =
684 coreSettings.getString(Settings.Global.GAME_DRIVER_SPHAL_LIBRARIES);
685
686 if (DEBUG) {
687 Log.v(TAG,
688 "gfx driver package search path: " + paths
689 + ", required sphal libraries: " + sphalLibraries);
690 }
691 setDriverPathAndSphalLibraries(paths, sphalLibraries);
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800692
Yiwei Zhangf7b0a5f2019-02-19 16:04:10 -0800693 if (driverAppInfo.metaData == null) {
694 throw new NullPointerException("apk's meta-data cannot be null");
695 }
696
697 final String driverBuildTime = driverAppInfo.metaData.getString(METADATA_DRIVER_BUILD_TIME);
698 if (driverBuildTime == null || driverBuildTime.isEmpty()) {
699 throw new IllegalArgumentException("driver_build_time meta-data is not set");
700 }
701 // driver_build_time in the meta-data is in "L<Unix epoch timestamp>" format. e.g. L123456.
702 // Long.parseLong will throw if the meta-data "driver_build_time" is not set properly.
Yiwei Zhang31f5adb2019-02-15 16:15:17 -0800703 setGpuStats(driverPackageName, driverPackageInfo.versionName, driverAppInfo.longVersionCode,
Yiwei Zhangf7b0a5f2019-02-19 16:04:10 -0800704 Long.parseLong(driverBuildTime.substring(1)), packageName);
Yiwei Zhang31f5adb2019-02-15 16:15:17 -0800705
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800706 return true;
Jesse Hall79bf3922016-12-12 12:53:02 -0800707 }
708
Jesse Hall79bf3922016-12-12 12:53:02 -0800709 private static String chooseAbi(ApplicationInfo ai) {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800710 final String isa = VMRuntime.getCurrentInstructionSet();
Jesse Hall79bf3922016-12-12 12:53:02 -0800711 if (ai.primaryCpuAbi != null &&
712 isa.equals(VMRuntime.getInstructionSet(ai.primaryCpuAbi))) {
713 return ai.primaryCpuAbi;
714 }
715 if (ai.secondaryCpuAbi != null &&
716 isa.equals(VMRuntime.getInstructionSet(ai.secondaryCpuAbi))) {
717 return ai.secondaryCpuAbi;
718 }
719 return null;
720 }
721
Cody Northropebe6a562018-10-15 07:22:23 -0600722 private static native int getCanLoadSystemLibraries();
Cody Northrop86cedcb2017-10-20 09:03:13 -0600723 private static native void setLayerPaths(ClassLoader classLoader, String layerPaths);
724 private static native void setDebugLayers(String layers);
Cody Northrop0fa1d222018-10-23 13:13:21 -0600725 private static native void setDebugLayersGLES(String layers);
Yiwei Zhang1c51f052019-02-14 12:05:47 -0800726 private static native void setDriverPathAndSphalLibraries(String path, String sphalLibraries);
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800727 private static native void setGpuStats(String driverPackageName, String driverVersionName,
Yiwei Zhangf7b0a5f2019-02-19 16:04:10 -0800728 long driverVersionCode, long driverBuildTime, String appPackageName);
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800729 private static native void setAngleInfo(String path, String appPackage, String devOptIn,
730 FileDescriptor rulesFd, long rulesOffset, long rulesLength);
Tim Van Pattenddc43912018-12-18 17:47:52 -0700731 private static native boolean getShouldUseAngle(String packageName);
Jesse Hall79bf3922016-12-12 12:53:02 -0800732}