blob: 7a70e93b69d546d870cd79ccd23a91de6a8b2966 [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
Yiwei Zhange3490fc2019-06-13 14:02:35 -070036import java.io.BufferedReader;
Jesse Hall79bf3922016-12-12 12:53:02 -080037import java.io.File;
Cody Northrop7fd44212018-09-06 10:30:28 -060038import java.io.FileDescriptor;
Cody Northrop8d72a6b2018-11-01 08:20:26 -060039import java.io.FileInputStream;
40import java.io.FileNotFoundException;
Peiyong Lin88c38eb2018-10-12 15:34:15 -070041import java.io.IOException;
Yiwei Zhange3490fc2019-06-13 14:02:35 -070042import java.io.InputStreamReader;
Tim Van Patten3c612842018-11-09 16:48:24 -070043import java.util.ArrayList;
44import java.util.Arrays;
45import java.util.HashMap;
46import java.util.List;
47import java.util.Map;
Jesse Hall79bf3922016-12-12 12:53:02 -080048
49/** @hide */
Cody Northrop86cedcb2017-10-20 09:03:13 -060050public class GraphicsEnvironment {
51
52 private static final GraphicsEnvironment sInstance = new GraphicsEnvironment();
53
54 /**
55 * Returns the shared {@link GraphicsEnvironment} instance.
56 */
57 public static GraphicsEnvironment getInstance() {
58 return sInstance;
59 }
Jesse Hall79bf3922016-12-12 12:53:02 -080060
61 private static final boolean DEBUG = false;
62 private static final String TAG = "GraphicsEnvironment";
Yiwei Zhang33097bf2019-02-04 19:01:21 -080063 private static final String SYSTEM_DRIVER_NAME = "system";
64 private static final String SYSTEM_DRIVER_VERSION_NAME = "";
65 private static final long SYSTEM_DRIVER_VERSION_CODE = 0;
Jesse Hall79bf3922016-12-12 12:53:02 -080066 private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0";
Yiwei Zhang5d0d4c62019-06-09 23:29:59 -070067 private static final String PROPERTY_GFX_DRIVER_PRERELEASE = "ro.gfx.driver.1";
Yiwei Zhangf7b0a5f2019-02-19 16:04:10 -080068 private static final String PROPERTY_GFX_DRIVER_BUILD_TIME = "ro.gfx.driver_build_time";
Yiwei Zhang61f8d222019-03-21 16:14:54 -070069 private static final String METADATA_DRIVER_BUILD_TIME = "com.android.gamedriver.build_time";
Peiyong Lin7797b4d2019-08-09 10:34:39 -070070 private static final String METADATA_DEVELOPER_DRIVER_ENABLE =
71 "com.android.graphics.developerdriver.enable";
Cody Northrop7fd44212018-09-06 10:30:28 -060072 private static final String ANGLE_RULES_FILE = "a4a_rules.json";
Cody Northrop8d72a6b2018-11-01 08:20:26 -060073 private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -070074 private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID";
Tim Van Pattenb225b442019-03-07 09:35:26 -070075 private static final String ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE =
76 "android.app.action.ANGLE_FOR_ANDROID_TOAST_MESSAGE";
77 private static final String INTENT_KEY_A4A_TOAST_MESSAGE = "A4A Toast Message";
Peiyong Linb76bfe92019-02-13 14:46:54 -080078 private static final String GAME_DRIVER_WHITELIST_ALL = "*";
Yiwei Zhange3490fc2019-06-13 14:02:35 -070079 private static final String GAME_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt";
Yiwei Zhang27a27432019-05-06 17:13:05 -070080 private static final int VULKAN_1_0 = 0x00400000;
81 private static final int VULKAN_1_1 = 0x00401000;
Jesse Hall79bf3922016-12-12 12:53:02 -080082
Peiyong Lin9eee3f92019-04-09 17:16:20 -070083 // GAME_DRIVER_ALL_APPS
84 // 0: Default (Invalid values fallback to default as well)
85 // 1: All apps use Game Driver
Yiwei Zhangff9a4ee2019-06-12 14:10:17 -070086 // 2: All apps use Prerelease Driver
87 // 3: All apps use system graphics driver
Peiyong Lin9eee3f92019-04-09 17:16:20 -070088 private static final int GAME_DRIVER_GLOBAL_OPT_IN_DEFAULT = 0;
Yiwei Zhangff9a4ee2019-06-12 14:10:17 -070089 private static final int GAME_DRIVER_GLOBAL_OPT_IN_GAME_DRIVER = 1;
90 private static final int GAME_DRIVER_GLOBAL_OPT_IN_PRERELEASE_DRIVER = 2;
91 private static final int GAME_DRIVER_GLOBAL_OPT_IN_OFF = 3;
Peiyong Lin9eee3f92019-04-09 17:16:20 -070092
Cody Northrop86cedcb2017-10-20 09:03:13 -060093 private ClassLoader mClassLoader;
94 private String mLayerPath;
95 private String mDebugLayerPath;
96
97 /**
98 * Set up GraphicsEnvironment
99 */
Cody Northropdeb43282018-10-04 16:04:05 -0600100 public void setup(Context context, Bundle coreSettings) {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800101 final PackageManager pm = context.getPackageManager();
102 final String packageName = context.getPackageName();
Yiwei Zhange6bdc382019-03-18 22:16:42 -0700103 Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers");
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800104 setupGpuLayers(context, coreSettings, pm, packageName);
Yiwei Zhange6bdc382019-03-18 22:16:42 -0700105 Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
106 Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupAngle");
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800107 setupAngle(context, coreSettings, pm, packageName);
Yiwei Zhange6bdc382019-03-18 22:16:42 -0700108 Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
109 Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "chooseDriver");
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800110 if (!chooseDriver(context, coreSettings, pm, packageName)) {
111 setGpuStats(SYSTEM_DRIVER_NAME, SYSTEM_DRIVER_VERSION_NAME, SYSTEM_DRIVER_VERSION_CODE,
Yiwei Zhang27a27432019-05-06 17:13:05 -0700112 SystemProperties.getLong(PROPERTY_GFX_DRIVER_BUILD_TIME, 0), packageName,
113 getVulkanVersion(pm));
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800114 }
Yiwei Zhange6bdc382019-03-18 22:16:42 -0700115 Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600116 }
117
118 /**
Yiwei Zhange54faf52019-05-08 18:43:11 -0700119 * Hint for GraphicsEnvironment that an activity is launching on the process.
120 * Then the app process is allowed to send stats to GpuStats module.
121 */
122 public static native void hintActivityLaunch();
123
124 /**
Cody Northrop12d320a2019-04-09 20:39:20 -0600125 * Query to determine if ANGLE should be used
126 */
127 public static boolean shouldUseAngle(Context context, Bundle coreSettings,
128 String packageName) {
129 if (packageName.isEmpty()) {
130 Log.v(TAG, "No package name available yet, ANGLE should not be used");
131 return false;
132 }
133
134 final String devOptIn = getDriverForPkg(context, coreSettings, packageName);
135 if (DEBUG) {
136 Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
137 + "set to: '" + devOptIn + "'");
138 }
139
140 // We only want to use ANGLE if the app is whitelisted or the developer has
141 // explicitly chosen something other than default driver.
142 // The whitelist will be generated by the ANGLE APK at both boot time and
143 // ANGLE update time. It will only include apps mentioned in the rules file.
144 final boolean whitelisted = checkAngleWhitelist(context, coreSettings, packageName);
145 final boolean requested = devOptIn.equals(sDriverMap.get(OpenGlDriverChoice.ANGLE));
146 final boolean useAngle = (whitelisted || requested);
147 if (!useAngle) {
148 return false;
149 }
150
151 if (whitelisted) {
152 Log.v(TAG, "ANGLE whitelist includes " + packageName);
153 }
154 if (requested) {
155 Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
156 }
157
158 return true;
159 }
160
Yiwei Zhang27a27432019-05-06 17:13:05 -0700161 private static int getVulkanVersion(PackageManager pm) {
162 // PackageManager doesn't have an API to retrieve the version of a specific feature, and we
163 // need to avoid retrieving all system features here and looping through them.
164 if (pm.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, VULKAN_1_1)) {
165 return VULKAN_1_1;
166 }
167
168 if (pm.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, VULKAN_1_0)) {
169 return VULKAN_1_0;
170 }
171
172 return 0;
173 }
174
Cody Northrop12d320a2019-04-09 20:39:20 -0600175 /**
Cody Northrop86cedcb2017-10-20 09:03:13 -0600176 * Check whether application is debuggable
177 */
178 private static boolean isDebuggable(Context context) {
179 return (context.getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE) > 0;
180 }
181
182 /**
183 * Store the layer paths available to the loader.
184 */
185 public void setLayerPaths(ClassLoader classLoader,
186 String layerPath,
187 String debugLayerPath) {
188 // We have to store these in the class because they are set up before we
189 // have access to the Context to properly set up GraphicsEnvironment
190 mClassLoader = classLoader;
191 mLayerPath = layerPath;
192 mDebugLayerPath = debugLayerPath;
193 }
194
195 /**
Cody Northropebe6a562018-10-15 07:22:23 -0600196 * Return the debug layer app's on-disk and in-APK lib directories
197 */
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800198 private static String getDebugLayerAppPaths(PackageManager pm, String app) {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800199 final ApplicationInfo appInfo;
Cody Northropebe6a562018-10-15 07:22:23 -0600200 try {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800201 appInfo = pm.getApplicationInfo(app, PackageManager.MATCH_ALL);
Cody Northropebe6a562018-10-15 07:22:23 -0600202 } catch (PackageManager.NameNotFoundException e) {
203 Log.w(TAG, "Debug layer app '" + app + "' not installed");
204
205 return null;
206 }
207
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800208 final String abi = chooseAbi(appInfo);
Cody Northropebe6a562018-10-15 07:22:23 -0600209
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800210 final StringBuilder sb = new StringBuilder();
Cody Northropebe6a562018-10-15 07:22:23 -0600211 sb.append(appInfo.nativeLibraryDir)
212 .append(File.pathSeparator);
213 sb.append(appInfo.sourceDir)
214 .append("!/lib/")
215 .append(abi);
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800216 final String paths = sb.toString();
Cody Northropebe6a562018-10-15 07:22:23 -0600217
218 if (DEBUG) Log.v(TAG, "Debug layer app libs: " + paths);
219
220 return paths;
221 }
222
223 /**
Cody Northrop86cedcb2017-10-20 09:03:13 -0600224 * Set up layer search paths for all apps
225 * If debuggable, check for additional debug settings
226 */
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800227 private void setupGpuLayers(
228 Context context, Bundle coreSettings, PackageManager pm, String packageName) {
Cody Northrop86cedcb2017-10-20 09:03:13 -0600229 String layerPaths = "";
230
231 // Only enable additional debug functionality if the following conditions are met:
Cody Northropc558c0c2019-05-28 11:56:37 -0600232 // 1. App is debuggable or device is rooted
Cody Northrop86cedcb2017-10-20 09:03:13 -0600233 // 2. ENABLE_GPU_DEBUG_LAYERS is true
234 // 3. Package name is equal to GPU_DEBUG_APP
235
Cody Northropc558c0c2019-05-28 11:56:37 -0600236 if (isDebuggable(context) || (getCanLoadSystemLibraries() == 1)) {
Cody Northrop86cedcb2017-10-20 09:03:13 -0600237
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800238 final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600239
240 if (enable != 0) {
241
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800242 final String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600243
Cody Northrop86cedcb2017-10-20 09:03:13 -0600244 if ((gpuDebugApp != null && packageName != null)
245 && (!gpuDebugApp.isEmpty() && !packageName.isEmpty())
246 && gpuDebugApp.equals(packageName)) {
247 Log.i(TAG, "GPU debug layers enabled for " + packageName);
248
249 // Prepend the debug layer path as a searchable path.
250 // This will ensure debug layers added will take precedence over
251 // the layers specified by the app.
252 layerPaths = mDebugLayerPath + ":";
253
Cody Northropebe6a562018-10-15 07:22:23 -0600254 // If there is a debug layer app specified, add its path.
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800255 final String gpuDebugLayerApp =
Cody Northropebe6a562018-10-15 07:22:23 -0600256 coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP);
257
258 if (gpuDebugLayerApp != null && !gpuDebugLayerApp.isEmpty()) {
259 Log.i(TAG, "GPU debug layer app: " + gpuDebugLayerApp);
Cody Northropf959f6b2019-04-08 09:50:23 -0600260 // If a colon is present, treat this as multiple apps, so Vulkan and GLES
261 // layer apps can be provided at the same time.
262 String[] layerApps = gpuDebugLayerApp.split(":");
263 for (int i = 0; i < layerApps.length; i++) {
264 String paths = getDebugLayerAppPaths(pm, layerApps[i]);
265 if (paths != null) {
266 // Append the path so files placed in the app's base directory will
267 // override the external path
268 layerPaths += paths + ":";
269 }
Cody Northropebe6a562018-10-15 07:22:23 -0600270 }
271 }
272
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800273 final String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600274
Cody Northrop0fa1d222018-10-23 13:13:21 -0600275 Log.i(TAG, "Vulkan debug layer list: " + layers);
Cody Northrop86cedcb2017-10-20 09:03:13 -0600276 if (layers != null && !layers.isEmpty()) {
277 setDebugLayers(layers);
278 }
Cody Northrop0fa1d222018-10-23 13:13:21 -0600279
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800280 final String layersGLES =
Cody Northrop0fa1d222018-10-23 13:13:21 -0600281 coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS_GLES);
282
283 Log.i(TAG, "GLES debug layer list: " + layersGLES);
284 if (layersGLES != null && !layersGLES.isEmpty()) {
285 setDebugLayersGLES(layersGLES);
286 }
Cody Northrop86cedcb2017-10-20 09:03:13 -0600287 }
288 }
Cody Northrop86cedcb2017-10-20 09:03:13 -0600289 }
290
291 // Include the app's lib directory in all cases
292 layerPaths += mLayerPath;
293
294 setLayerPaths(mClassLoader, layerPaths);
295 }
296
Tim Van Patten3c612842018-11-09 16:48:24 -0700297 enum OpenGlDriverChoice {
298 DEFAULT,
299 NATIVE,
300 ANGLE
301 }
302
303 private static final Map<OpenGlDriverChoice, String> sDriverMap = buildMap();
304 private static Map<OpenGlDriverChoice, String> buildMap() {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800305 final Map<OpenGlDriverChoice, String> map = new HashMap<>();
Tim Van Patten3c612842018-11-09 16:48:24 -0700306 map.put(OpenGlDriverChoice.DEFAULT, "default");
307 map.put(OpenGlDriverChoice.ANGLE, "angle");
308 map.put(OpenGlDriverChoice.NATIVE, "native");
309
310 return map;
311 }
312
313
Tim Van Pattenddc43912018-12-18 17:47:52 -0700314 private static List<String> getGlobalSettingsString(ContentResolver contentResolver,
315 Bundle bundle,
316 String globalSetting) {
317 final List<String> valueList;
318 final String settingsValue;
319
320 if (bundle != null) {
321 settingsValue = bundle.getString(globalSetting);
322 } else {
323 settingsValue = Settings.Global.getString(contentResolver, globalSetting);
324 }
Tim Van Patten3c612842018-11-09 16:48:24 -0700325
326 if (settingsValue != null) {
327 valueList = new ArrayList<>(Arrays.asList(settingsValue.split(",")));
328 } else {
329 valueList = new ArrayList<>();
330 }
331
332 return valueList;
333 }
334
335 private static int getGlobalSettingsPkgIndex(String pkgName,
336 List<String> globalSettingsDriverPkgs) {
337 for (int pkgIndex = 0; pkgIndex < globalSettingsDriverPkgs.size(); pkgIndex++) {
338 if (globalSettingsDriverPkgs.get(pkgIndex).equals(pkgName)) {
339 return pkgIndex;
340 }
341 }
342
343 return -1;
344 }
345
Tim Van Pattenddc43912018-12-18 17:47:52 -0700346 private static String getDriverForPkg(Context context, Bundle bundle, String packageName) {
347 final String allUseAngle;
348 if (bundle != null) {
349 allUseAngle =
350 bundle.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
351 } else {
352 ContentResolver contentResolver = context.getContentResolver();
353 allUseAngle = Settings.Global.getString(contentResolver,
354 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_ALL_ANGLE);
355 }
Tim Van Pattenff9476b2018-12-11 15:41:25 -0700356 if ((allUseAngle != null) && allUseAngle.equals("1")) {
357 return sDriverMap.get(OpenGlDriverChoice.ANGLE);
Tim Van Patten3c612842018-11-09 16:48:24 -0700358 }
359
Tim Van Pattenddc43912018-12-18 17:47:52 -0700360 final ContentResolver contentResolver = context.getContentResolver();
361 final List<String> globalSettingsDriverPkgs =
362 getGlobalSettingsString(contentResolver, bundle,
363 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_PKGS);
364 final List<String> globalSettingsDriverValues =
365 getGlobalSettingsString(contentResolver, bundle,
366 Settings.Global.GLOBAL_SETTINGS_ANGLE_GL_DRIVER_SELECTION_VALUES);
Tim Van Patten3c612842018-11-09 16:48:24 -0700367
368 // Make sure we have a good package name
369 if ((packageName == null) || (packageName.isEmpty())) {
370 return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
371 }
372 // Make sure we have good settings to use
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700373 if (globalSettingsDriverPkgs.size() != globalSettingsDriverValues.size()) {
Tim Van Patten3c612842018-11-09 16:48:24 -0700374 Log.w(TAG,
375 "Global.Settings values are invalid: "
376 + "globalSettingsDriverPkgs.size = "
377 + globalSettingsDriverPkgs.size() + ", "
378 + "globalSettingsDriverValues.size = "
379 + globalSettingsDriverValues.size());
380 return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
381 }
382
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800383 final int pkgIndex = getGlobalSettingsPkgIndex(packageName, globalSettingsDriverPkgs);
Tim Van Patten3c612842018-11-09 16:48:24 -0700384
385 if (pkgIndex < 0) {
386 return sDriverMap.get(OpenGlDriverChoice.DEFAULT);
387 }
388
389 return globalSettingsDriverValues.get(pkgIndex);
390 }
391
Jesse Hallc37984f2017-05-23 16:55:08 -0700392 /**
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700393 * Get the ANGLE package name.
394 */
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800395 private String getAnglePackageName(PackageManager pm) {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800396 final Intent intent = new Intent(ACTION_ANGLE_FOR_ANDROID);
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700397
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800398 final List<ResolveInfo> resolveInfos =
399 pm.queryIntentActivities(intent, PackageManager.MATCH_SYSTEM_ONLY);
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700400 if (resolveInfos.size() != 1) {
401 Log.e(TAG, "Invalid number of ANGLE packages. Required: 1, Found: "
402 + resolveInfos.size());
403 for (ResolveInfo resolveInfo : resolveInfos) {
404 Log.e(TAG, "Found ANGLE package: " + resolveInfo.activityInfo.packageName);
405 }
406 return "";
407 }
408
409 // Must be exactly 1 ANGLE PKG found to get here.
410 return resolveInfos.get(0).activityInfo.packageName;
411 }
412
413 /**
Cody Northropdc2fd942019-03-28 19:27:19 -0600414 * Check for ANGLE debug package, but only for apps that can load them (dumpable)
415 */
416 private String getAngleDebugPackage(Context context, Bundle coreSettings) {
417 final boolean appIsDebuggable = isDebuggable(context);
Cody Northropdc2fd942019-03-28 19:27:19 -0600418 final boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
Cody Northrop32adba42019-05-28 12:18:44 -0600419 if (appIsDebuggable || deviceIsDebuggable) {
Tim Van Patten5973ec92019-04-08 17:30:17 -0600420 String debugPackage;
Cody Northropdc2fd942019-03-28 19:27:19 -0600421
Tim Van Patten5973ec92019-04-08 17:30:17 -0600422 if (coreSettings != null) {
423 debugPackage =
424 coreSettings.getString(Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE);
425 } else {
426 ContentResolver contentResolver = context.getContentResolver();
427 debugPackage = Settings.Global.getString(contentResolver,
428 Settings.Global.GLOBAL_SETTINGS_ANGLE_DEBUG_PACKAGE);
429 }
Cody Northropdc2fd942019-03-28 19:27:19 -0600430
431 if ((debugPackage != null) && (!debugPackage.isEmpty())) {
432 return debugPackage;
433 }
434 }
Tim Van Patten5973ec92019-04-08 17:30:17 -0600435
Cody Northropdc2fd942019-03-28 19:27:19 -0600436 return "";
437 }
438
439 /**
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700440 * Attempt to setup ANGLE with a temporary rules file.
441 * True: Temporary rules file was loaded.
442 * False: Temporary rules file was *not* loaded.
443 */
Tim Van Pattenddc43912018-12-18 17:47:52 -0700444 private static boolean setupAngleWithTempRulesFile(Context context,
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700445 String packageName,
446 String paths,
447 String devOptIn) {
Tim Van Patten3df66432019-01-14 15:56:12 -0700448 /**
449 * We only want to load a temp rules file for:
450 * - apps that are marked 'debuggable' in their manifest
451 * - devices that are running a userdebug build (ro.debuggable) or can inject libraries for
452 * debugging (PR_SET_DUMPABLE).
453 */
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800454 final boolean appIsDebuggable = isDebuggable(context);
455 final boolean deviceIsDebuggable = getCanLoadSystemLibraries() == 1;
Tim Van Patten3df66432019-01-14 15:56:12 -0700456 if (!(appIsDebuggable || deviceIsDebuggable)) {
457 Log.v(TAG, "Skipping loading temporary rules file: "
458 + "appIsDebuggable = " + appIsDebuggable + ", "
459 + "adbRootEnabled = " + deviceIsDebuggable);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700460 return false;
461 }
462
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800463 final String angleTempRules = SystemProperties.get(ANGLE_TEMP_RULES);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700464
465 if ((angleTempRules == null) || angleTempRules.isEmpty()) {
466 Log.v(TAG, "System property '" + ANGLE_TEMP_RULES + "' is not set or is empty");
467 return false;
468 }
469
470 Log.i(TAG, "Detected system property " + ANGLE_TEMP_RULES + ": " + angleTempRules);
471
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800472 final File tempRulesFile = new File(angleTempRules);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700473 if (tempRulesFile.exists()) {
474 Log.i(TAG, angleTempRules + " exists, loading file.");
475 try {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800476 final FileInputStream stream = new FileInputStream(angleTempRules);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700477
478 try {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800479 final FileDescriptor rulesFd = stream.getFD();
480 final long rulesOffset = 0;
481 final long rulesLength = stream.getChannel().size();
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700482 Log.i(TAG, "Loaded temporary ANGLE rules from " + angleTempRules);
483
484 setAngleInfo(paths, packageName, devOptIn, rulesFd, rulesOffset, rulesLength);
485
486 stream.close();
487
488 // We successfully setup ANGLE, so return with good status
489 return true;
490 } catch (IOException e) {
491 Log.w(TAG, "Hit IOException thrown by FileInputStream: " + e);
492 }
493 } catch (FileNotFoundException e) {
494 Log.w(TAG, "Temp ANGLE rules file not found: " + e);
495 } catch (SecurityException e) {
496 Log.w(TAG, "Temp ANGLE rules file not accessible: " + e);
497 }
498 }
499
500 return false;
501 }
502
503 /**
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700504 * Attempt to setup ANGLE with a rules file loaded from the ANGLE APK.
505 * True: APK rules file was loaded.
506 * False: APK rules file was *not* loaded.
507 */
Tim Van Pattenddc43912018-12-18 17:47:52 -0700508 private static boolean setupAngleRulesApk(String anglePkgName,
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700509 ApplicationInfo angleInfo,
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800510 PackageManager pm,
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700511 String packageName,
512 String paths,
513 String devOptIn) {
514 // Pass the rules file to loader for ANGLE decisions
515 try {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800516 final AssetManager angleAssets = pm.getResourcesForApplication(angleInfo).getAssets();
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700517
518 try {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800519 final AssetFileDescriptor assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700520
521 setAngleInfo(paths, packageName, devOptIn, assetsFd.getFileDescriptor(),
522 assetsFd.getStartOffset(), assetsFd.getLength());
523
524 assetsFd.close();
525
526 return true;
527 } catch (IOException e) {
528 Log.w(TAG, "Failed to get AssetFileDescriptor for " + ANGLE_RULES_FILE
529 + " from '" + anglePkgName + "': " + e);
530 }
531 } catch (PackageManager.NameNotFoundException e) {
532 Log.w(TAG, "Failed to get AssetManager for '" + anglePkgName + "': " + e);
533 }
534
535 return false;
536 }
537
538 /**
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700539 * Pull ANGLE whitelist from GlobalSettings and compare against current package
540 */
Tim Van Pattenddc43912018-12-18 17:47:52 -0700541 private static boolean checkAngleWhitelist(Context context, Bundle bundle, String packageName) {
542 final ContentResolver contentResolver = context.getContentResolver();
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800543 final List<String> angleWhitelist =
Tim Van Pattenddc43912018-12-18 17:47:52 -0700544 getGlobalSettingsString(contentResolver, bundle,
545 Settings.Global.GLOBAL_SETTINGS_ANGLE_WHITELIST);
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700546
Cody Northrop12d320a2019-04-09 20:39:20 -0600547 if (DEBUG) Log.v(TAG, "ANGLE whitelist: " + angleWhitelist);
548
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700549 return angleWhitelist.contains(packageName);
550 }
551
552 /**
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600553 * Pass ANGLE details down to trigger enable logic
Tim Van Pattenddc43912018-12-18 17:47:52 -0700554 *
555 * @param context
556 * @param bundle
557 * @param packageName
558 * @return true: ANGLE setup successfully
559 * false: ANGLE not setup (not on whitelist, ANGLE not present, etc.)
Cody Northrop73c05042018-04-16 13:23:51 -0600560 */
Tim Van Pattenddc43912018-12-18 17:47:52 -0700561 public boolean setupAngle(Context context, Bundle bundle, PackageManager pm,
562 String packageName) {
Cody Northrop12d320a2019-04-09 20:39:20 -0600563
564 if (!shouldUseAngle(context, bundle, packageName)) {
Tim Van Pattenddc43912018-12-18 17:47:52 -0700565 return false;
Cody Northrop5ebb0db2019-01-15 14:06:36 -0700566 }
Cody Northrop73c05042018-04-16 13:23:51 -0600567
Cody Northrop41149c32019-05-06 11:36:40 -0600568 ApplicationInfo angleInfo = null;
Tim Van Patten5e3e2ae2018-12-13 17:43:37 -0700569
Cody Northrop41149c32019-05-06 11:36:40 -0600570 // If the developer has specified a debug package over ADB, attempt to find it
571 String anglePkgName = getAngleDebugPackage(context, bundle);
572 if (!anglePkgName.isEmpty()) {
573 Log.i(TAG, "ANGLE debug package enabled: " + anglePkgName);
Cody Northropdc2fd942019-03-28 19:27:19 -0600574 try {
575 // Note the debug package does not have to be pre-installed
Cody Northrop41149c32019-05-06 11:36:40 -0600576 angleInfo = pm.getApplicationInfo(anglePkgName, 0);
Cody Northropdc2fd942019-03-28 19:27:19 -0600577 } catch (PackageManager.NameNotFoundException e) {
Cody Northrop41149c32019-05-06 11:36:40 -0600578 Log.w(TAG, "ANGLE debug package '" + anglePkgName + "' not installed");
Cody Northropdc2fd942019-03-28 19:27:19 -0600579 return false;
580 }
Cody Northrop41149c32019-05-06 11:36:40 -0600581 }
582
583 // Otherwise, check to see if ANGLE is properly installed
584 if (angleInfo == null) {
585 anglePkgName = getAnglePackageName(pm);
586 if (!anglePkgName.isEmpty()) {
587 Log.i(TAG, "ANGLE package enabled: " + anglePkgName);
588 try {
589 // Production ANGLE libraries must be pre-installed as a system app
590 angleInfo = pm.getApplicationInfo(anglePkgName,
591 PackageManager.MATCH_SYSTEM_ONLY);
592 } catch (PackageManager.NameNotFoundException e) {
593 Log.w(TAG, "ANGLE package '" + anglePkgName + "' not installed");
594 return false;
595 }
596 } else {
597 Log.e(TAG, "Failed to find ANGLE package.");
Cody Northropdc2fd942019-03-28 19:27:19 -0600598 return false;
599 }
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600600 }
601
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800602 final String abi = chooseAbi(angleInfo);
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600603
604 // Build a path that includes installed native libs and APK
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800605 final String paths = angleInfo.nativeLibraryDir
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700606 + File.pathSeparator
607 + angleInfo.sourceDir
608 + "!/lib/"
609 + abi;
Cody Northropeb0ca8e2018-08-09 16:01:08 -0600610
611 if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
612
Cody Northrop12d320a2019-04-09 20:39:20 -0600613 // If the user has set the developer option to something other than default,
614 // we need to call setupAngleRulesApk() with the package name and the developer
615 // option value (native/angle/other). Then later when we are actually trying to
616 // load a driver, GraphicsEnv::getShouldUseAngle() has seen the package name before
617 // and can confidently answer yes/no based on the previously set developer
618 // option value.
619 final String devOptIn = getDriverForPkg(context, bundle, packageName);
620
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700621 if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) {
622 // We setup ANGLE with a temp rules file, so we're done here.
Tim Van Pattenddc43912018-12-18 17:47:52 -0700623 return true;
Cody Northrop8d72a6b2018-11-01 08:20:26 -0600624 }
625
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800626 if (setupAngleRulesApk(anglePkgName, angleInfo, pm, packageName, paths, devOptIn)) {
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700627 // We setup ANGLE with rules from the APK, so we're done here.
Tim Van Pattenddc43912018-12-18 17:47:52 -0700628 return true;
629 }
630
631 return false;
632 }
633
634 /**
635 * Determine if the "ANGLE In Use" dialog box should be shown.
636 */
637 private boolean shouldShowAngleInUseDialogBox(Context context) {
638 try {
639 ContentResolver contentResolver = context.getContentResolver();
640 final int showDialogBox = Settings.Global.getInt(contentResolver,
641 Settings.Global.GLOBAL_SETTINGS_SHOW_ANGLE_IN_USE_DIALOG_BOX);
642
643 return (showDialogBox == 1);
644 } catch (Settings.SettingNotFoundException | SecurityException e) {
645 // Do nothing and move on
646 }
647
648 // No setting, so assume false
649 return false;
650 }
651
652 /**
Cody Northrop12d320a2019-04-09 20:39:20 -0600653 * Determine if ANGLE will be used and setup the environment
Tim Van Pattenddc43912018-12-18 17:47:52 -0700654 */
Cody Northrop12d320a2019-04-09 20:39:20 -0600655 private boolean setupAndUseAngle(Context context, String packageName) {
Tim Van Pattenddc43912018-12-18 17:47:52 -0700656 // Need to make sure we are evaluating ANGLE usage for the correct circumstances
657 if (!setupAngle(context, null, context.getPackageManager(), packageName)) {
Cody Northrop41149c32019-05-06 11:36:40 -0600658 Log.v(TAG, "Package '" + packageName + "' should not use ANGLE");
Tim Van Pattenddc43912018-12-18 17:47:52 -0700659 return false;
660 }
661
662 final boolean useAngle = getShouldUseAngle(packageName);
663 Log.v(TAG, "Package '" + packageName + "' should use ANGLE = '" + useAngle + "'");
664
665 return useAngle;
666 }
667
668 /**
669 * Show the ANGLE in Use Dialog Box
670 * @param context
671 */
672 public void showAngleInUseDialogBox(Context context) {
673 final String packageName = context.getPackageName();
674
Cody Northrop12d320a2019-04-09 20:39:20 -0600675 if (shouldShowAngleInUseDialogBox(context) && setupAndUseAngle(context, packageName)) {
Tim Van Pattenb225b442019-03-07 09:35:26 -0700676 final Intent intent = new Intent(ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE);
677 String anglePkg = getAnglePackageName(context.getPackageManager());
678 intent.setPackage(anglePkg);
679
680 context.sendOrderedBroadcast(intent, null, new BroadcastReceiver() {
681 @Override
682 public void onReceive(Context context, Intent intent) {
683 Bundle results = getResultExtras(true);
684
685 String toastMsg = results.getString(INTENT_KEY_A4A_TOAST_MESSAGE);
686 final Toast toast = Toast.makeText(context, toastMsg, Toast.LENGTH_LONG);
687 toast.show();
688 }
689 }, null, Activity.RESULT_OK, null, null);
Tim Van Pattena7577bf2018-12-12 11:47:24 -0700690 }
Cody Northrop73c05042018-04-16 13:23:51 -0600691 }
692
693 /**
Yiwei Zhang5d0d4c62019-06-09 23:29:59 -0700694 * Return the driver package name to use. Return null for system driver.
695 */
Peiyong Lin7797b4d2019-08-09 10:34:39 -0700696 private static String chooseDriverInternal(
697 Context context, Bundle coreSettings, PackageManager pm, String packageName) {
Yiwei Zhang5d0d4c62019-06-09 23:29:59 -0700698 final String gameDriver = SystemProperties.get(PROPERTY_GFX_DRIVER);
699 final boolean hasGameDriver = gameDriver != null && !gameDriver.isEmpty();
700
701 final String prereleaseDriver = SystemProperties.get(PROPERTY_GFX_DRIVER_PRERELEASE);
702 final boolean hasPrereleaseDriver = prereleaseDriver != null && !prereleaseDriver.isEmpty();
703
704 if (!hasGameDriver && !hasPrereleaseDriver) {
705 if (DEBUG) Log.v(TAG, "Neither Game Driver nor prerelease driver is supported.");
706 return null;
707 }
708
709 // To minimize risk of driver updates crippling the device beyond user repair, never use an
710 // updated driver for privileged or non-updated system apps. Presumably pre-installed apps
711 // were tested thoroughly with the pre-installed driver.
Peiyong Lin7797b4d2019-08-09 10:34:39 -0700712 ApplicationInfo ai;
713 try {
714 // Get the ApplicationInfo from PackageManager so that metadata fields present.
715 ai = pm.getApplicationInfo(packageName, PackageManager.GET_META_DATA);
716 } catch (PackageManager.NameNotFoundException e) {
717 // Unlikely to fail for applications, but in case of failure, fall back to use the
718 // ApplicationInfo from context directly.
719 ai = context.getApplicationInfo();
720 }
Yiwei Zhang5d0d4c62019-06-09 23:29:59 -0700721 if (ai.isPrivilegedApp() || (ai.isSystemApp() && !ai.isUpdatedSystemApp())) {
722 if (DEBUG) Log.v(TAG, "Ignoring driver package for privileged/non-updated system app.");
723 return null;
724 }
725
Peiyong Lin7797b4d2019-08-09 10:34:39 -0700726 final boolean enablePrereleaseDriver =
727 (ai.metaData != null && ai.metaData.getBoolean(METADATA_DEVELOPER_DRIVER_ENABLE))
728 || getCanLoadSystemLibraries() == 1;
729
Yiwei Zhang5d0d4c62019-06-09 23:29:59 -0700730 // Priority for Game Driver settings global on confliction (Higher priority comes first):
731 // 1. GAME_DRIVER_ALL_APPS
732 // 2. GAME_DRIVER_OPT_OUT_APPS
733 // 3. GAME_DRIVER_PRERELEASE_OPT_IN_APPS
734 // 4. GAME_DRIVER_OPT_IN_APPS
735 // 5. GAME_DRIVER_BLACKLIST
736 // 6. GAME_DRIVER_WHITELIST
Yiwei Zhangff9a4ee2019-06-12 14:10:17 -0700737 switch (coreSettings.getInt(Settings.Global.GAME_DRIVER_ALL_APPS, 0)) {
738 case GAME_DRIVER_GLOBAL_OPT_IN_OFF:
739 if (DEBUG) Log.v(TAG, "Game Driver is turned off on this device.");
740 return null;
741 case GAME_DRIVER_GLOBAL_OPT_IN_GAME_DRIVER:
742 if (DEBUG) Log.v(TAG, "All apps opt in to use Game Driver.");
743 return hasGameDriver ? gameDriver : null;
744 case GAME_DRIVER_GLOBAL_OPT_IN_PRERELEASE_DRIVER:
745 if (DEBUG) Log.v(TAG, "All apps opt in to use prerelease driver.");
Peiyong Lin7797b4d2019-08-09 10:34:39 -0700746 return hasPrereleaseDriver && enablePrereleaseDriver ? prereleaseDriver : null;
Yiwei Zhangff9a4ee2019-06-12 14:10:17 -0700747 case GAME_DRIVER_GLOBAL_OPT_IN_DEFAULT:
748 default:
749 break;
Yiwei Zhang5d0d4c62019-06-09 23:29:59 -0700750 }
751
752 final String appPackageName = ai.packageName;
753 if (getGlobalSettingsString(null, coreSettings, Settings.Global.GAME_DRIVER_OPT_OUT_APPS)
754 .contains(appPackageName)) {
755 if (DEBUG) Log.v(TAG, "App opts out for Game Driver.");
756 return null;
757 }
758
759 if (getGlobalSettingsString(
760 null, coreSettings, Settings.Global.GAME_DRIVER_PRERELEASE_OPT_IN_APPS)
761 .contains(appPackageName)) {
762 if (DEBUG) Log.v(TAG, "App opts in for prerelease Game Driver.");
Peiyong Lin7797b4d2019-08-09 10:34:39 -0700763 return hasPrereleaseDriver && enablePrereleaseDriver ? prereleaseDriver : null;
Yiwei Zhang5d0d4c62019-06-09 23:29:59 -0700764 }
765
766 // Early return here since the rest logic is only for Game Driver.
767 if (!hasGameDriver) {
768 if (DEBUG) Log.v(TAG, "Game Driver is not supported on the device.");
769 return null;
770 }
771
772 final boolean isOptIn =
773 getGlobalSettingsString(null, coreSettings, Settings.Global.GAME_DRIVER_OPT_IN_APPS)
774 .contains(appPackageName);
775 final List<String> whitelist =
776 getGlobalSettingsString(null, coreSettings, Settings.Global.GAME_DRIVER_WHITELIST);
777 if (!isOptIn && whitelist.indexOf(GAME_DRIVER_WHITELIST_ALL) != 0
778 && !whitelist.contains(appPackageName)) {
779 if (DEBUG) Log.v(TAG, "App is not on the whitelist for Game Driver.");
780 return null;
781 }
782
783 // If the application is not opted-in, then check whether it's on the blacklist,
784 // terminate early if it's on the blacklist and fallback to system driver.
785 if (!isOptIn
786 && getGlobalSettingsString(
787 null, coreSettings, Settings.Global.GAME_DRIVER_BLACKLIST)
788 .contains(appPackageName)) {
789 if (DEBUG) Log.v(TAG, "App is on the blacklist for Game Driver.");
790 return null;
791 }
792
793 return gameDriver;
794 }
795
796 /**
Jesse Hallc37984f2017-05-23 16:55:08 -0700797 * Choose whether the current process should use the builtin or an updated driver.
Jesse Hallc37984f2017-05-23 16:55:08 -0700798 */
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800799 private static boolean chooseDriver(
800 Context context, Bundle coreSettings, PackageManager pm, String packageName) {
Peiyong Lin7797b4d2019-08-09 10:34:39 -0700801 final String driverPackageName = chooseDriverInternal(context, coreSettings, pm,
802 packageName);
Yiwei Zhang5d0d4c62019-06-09 23:29:59 -0700803 if (driverPackageName == null) {
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800804 return false;
Jesse Hall79bf3922016-12-12 12:53:02 -0800805 }
Peiyong Lin2d5a2bb2018-11-07 21:10:07 -0800806
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800807 final PackageInfo driverPackageInfo;
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800808 try {
Yiwei Zhang31f5adb2019-02-15 16:15:17 -0800809 driverPackageInfo = pm.getPackageInfo(driverPackageName,
810 PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA);
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800811 } catch (PackageManager.NameNotFoundException e) {
812 Log.w(TAG, "driver package '" + driverPackageName + "' not installed");
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800813 return false;
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800814 }
815
816 // O drivers are restricted to the sphal linker namespace, so don't try to use
817 // packages unless they declare they're compatible with that restriction.
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800818 final ApplicationInfo driverAppInfo = driverPackageInfo.applicationInfo;
819 if (driverAppInfo.targetSdkVersion < Build.VERSION_CODES.O) {
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800820 if (DEBUG) {
821 Log.w(TAG, "updated driver package is not known to be compatible with O");
822 }
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800823 return false;
Peiyong Lin9ca1dd82019-01-12 17:44:29 -0800824 }
825
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800826 final String abi = chooseAbi(driverAppInfo);
Jesse Hall79bf3922016-12-12 12:53:02 -0800827 if (abi == null) {
828 if (DEBUG) {
829 // This is the normal case for the pre-installed empty driver package, don't spam
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800830 if (driverAppInfo.isUpdatedSystemApp()) {
Jesse Hall79bf3922016-12-12 12:53:02 -0800831 Log.w(TAG, "updated driver package has no compatible native libraries");
832 }
833 }
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800834 return false;
Jesse Hall79bf3922016-12-12 12:53:02 -0800835 }
Jesse Hall79bf3922016-12-12 12:53:02 -0800836
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800837 final StringBuilder sb = new StringBuilder();
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800838 sb.append(driverAppInfo.nativeLibraryDir)
Jesse Hall79bf3922016-12-12 12:53:02 -0800839 .append(File.pathSeparator);
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800840 sb.append(driverAppInfo.sourceDir)
Jesse Hall79bf3922016-12-12 12:53:02 -0800841 .append("!/lib/")
842 .append(abi);
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800843 final String paths = sb.toString();
Yiwei Zhange3490fc2019-06-13 14:02:35 -0700844 final String sphalLibraries = getSphalLibraries(context, driverPackageName);
Yiwei Zhang1c51f052019-02-14 12:05:47 -0800845 if (DEBUG) {
846 Log.v(TAG,
847 "gfx driver package search path: " + paths
848 + ", required sphal libraries: " + sphalLibraries);
849 }
850 setDriverPathAndSphalLibraries(paths, sphalLibraries);
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800851
Yiwei Zhangf7b0a5f2019-02-19 16:04:10 -0800852 if (driverAppInfo.metaData == null) {
853 throw new NullPointerException("apk's meta-data cannot be null");
854 }
855
856 final String driverBuildTime = driverAppInfo.metaData.getString(METADATA_DRIVER_BUILD_TIME);
857 if (driverBuildTime == null || driverBuildTime.isEmpty()) {
Yiwei Zhang61f8d222019-03-21 16:14:54 -0700858 throw new IllegalArgumentException("com.android.gamedriver.build_time is not set");
Yiwei Zhangf7b0a5f2019-02-19 16:04:10 -0800859 }
860 // driver_build_time in the meta-data is in "L<Unix epoch timestamp>" format. e.g. L123456.
861 // Long.parseLong will throw if the meta-data "driver_build_time" is not set properly.
Yiwei Zhang31f5adb2019-02-15 16:15:17 -0800862 setGpuStats(driverPackageName, driverPackageInfo.versionName, driverAppInfo.longVersionCode,
Yiwei Zhang27a27432019-05-06 17:13:05 -0700863 Long.parseLong(driverBuildTime.substring(1)), packageName, 0);
Yiwei Zhang31f5adb2019-02-15 16:15:17 -0800864
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800865 return true;
Jesse Hall79bf3922016-12-12 12:53:02 -0800866 }
867
Jesse Hall79bf3922016-12-12 12:53:02 -0800868 private static String chooseAbi(ApplicationInfo ai) {
Yiwei Zhanga0ee1f82019-02-04 17:53:57 -0800869 final String isa = VMRuntime.getCurrentInstructionSet();
Jesse Hall79bf3922016-12-12 12:53:02 -0800870 if (ai.primaryCpuAbi != null &&
871 isa.equals(VMRuntime.getInstructionSet(ai.primaryCpuAbi))) {
872 return ai.primaryCpuAbi;
873 }
874 if (ai.secondaryCpuAbi != null &&
875 isa.equals(VMRuntime.getInstructionSet(ai.secondaryCpuAbi))) {
876 return ai.secondaryCpuAbi;
877 }
878 return null;
879 }
880
Yiwei Zhange3490fc2019-06-13 14:02:35 -0700881 private static String getSphalLibraries(Context context, String driverPackageName) {
882 try {
883 final Context driverContext =
884 context.createPackageContext(driverPackageName, Context.CONTEXT_RESTRICTED);
885 final BufferedReader reader = new BufferedReader(new InputStreamReader(
886 driverContext.getAssets().open(GAME_DRIVER_SPHAL_LIBRARIES_FILENAME)));
887 final ArrayList<String> assetStrings = new ArrayList<>();
888 for (String assetString; (assetString = reader.readLine()) != null;) {
889 assetStrings.add(assetString);
890 }
891 return String.join(":", assetStrings);
892 } catch (PackageManager.NameNotFoundException e) {
893 if (DEBUG) {
894 Log.w(TAG, "Driver package '" + driverPackageName + "' not installed");
895 }
896 } catch (IOException e) {
897 if (DEBUG) {
898 Log.w(TAG, "Failed to load '" + GAME_DRIVER_SPHAL_LIBRARIES_FILENAME + "'");
899 }
900 }
901 return "";
902 }
903
Cody Northropebe6a562018-10-15 07:22:23 -0600904 private static native int getCanLoadSystemLibraries();
Cody Northrop86cedcb2017-10-20 09:03:13 -0600905 private static native void setLayerPaths(ClassLoader classLoader, String layerPaths);
906 private static native void setDebugLayers(String layers);
Cody Northrop0fa1d222018-10-23 13:13:21 -0600907 private static native void setDebugLayersGLES(String layers);
Yiwei Zhang1c51f052019-02-14 12:05:47 -0800908 private static native void setDriverPathAndSphalLibraries(String path, String sphalLibraries);
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800909 private static native void setGpuStats(String driverPackageName, String driverVersionName,
Yiwei Zhang27a27432019-05-06 17:13:05 -0700910 long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion);
Yiwei Zhang33097bf2019-02-04 19:01:21 -0800911 private static native void setAngleInfo(String path, String appPackage, String devOptIn,
912 FileDescriptor rulesFd, long rulesOffset, long rulesLength);
Tim Van Pattenddc43912018-12-18 17:47:52 -0700913 private static native boolean getShouldUseAngle(String packageName);
Jesse Hall79bf3922016-12-12 12:53:02 -0800914}