1 /* 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 17 package android.os; 18 19 import android.content.Context; 20 import android.content.pm.ApplicationInfo; 21 import android.content.pm.PackageManager; 22 import android.opengl.EGL14; 23 import android.os.Build; 24 import android.os.SystemProperties; 25 import android.util.Log; 26 27 import dalvik.system.VMRuntime; 28 29 import java.io.File; 30 31 /** @hide */ 32 public final class GraphicsEnvironment { 33 34 private static final boolean DEBUG = false; 35 private static final String TAG = "GraphicsEnvironment"; 36 private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0"; 37 38 public static void setupGraphicsEnvironment(Context context) { 39 chooseDriver(context); 40 41 // Now that we've figured out which driver to use for this process, load and initialize it. 42 // This can take multiple frame periods, and it would otherwise happen as part of the first 43 // frame, increasing first-frame latency. Starting it here, as a low-priority background 44 // thread, means that it's usually done long before we start drawing the first frame, 45 // without significantly disrupting other activity launch work. 46 Thread eglInitThread = new Thread( 47 () -> { 48 EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY); 49 }, 50 "EGL Init"); 51 eglInitThread.start(); 52 } 53 54 private static void chooseDriver(Context context) { 55 String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER); 56 if (driverPackageName == null || driverPackageName.isEmpty()) { 57 return; 58 } 59 // To minimize risk of driver updates crippling the device beyond user repair, never use an 60 // updated driver for privileged or non-updated system apps. Presumably pre-installed apps 61 // were tested thoroughly with the pre-installed driver. 62 ApplicationInfo ai = context.getApplicationInfo(); 63 if (ai.isPrivilegedApp() || (ai.isSystemApp() && !ai.isUpdatedSystemApp())) { 64 if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app"); 65 return; 66 } 67 ApplicationInfo driverInfo; 68 try { 69 driverInfo = context.getPackageManager().getApplicationInfo(driverPackageName, 70 PackageManager.MATCH_SYSTEM_ONLY); 71 } catch (PackageManager.NameNotFoundException e) { 72 Log.w(TAG, "driver package '" + driverPackageName + "' not installed"); 73 return; 74 } 75 String abi = chooseAbi(driverInfo); 76 if (abi == null) { 77 if (DEBUG) { 78 // This is the normal case for the pre-installed empty driver package, don't spam 79 if (driverInfo.isUpdatedSystemApp()) { 80 Log.w(TAG, "updated driver package has no compatible native libraries"); 81 } 82 } 83 return; 84 } 85 if (driverInfo.targetSdkVersion < Build.VERSION_CODES.O) { 86 // O drivers are restricted to the sphal linker namespace, so don't try to use 87 // packages unless they declare they're compatible with that restriction. 88 Log.w(TAG, "updated driver package is not known to be compatible with O"); 89 return; 90 } 91 92 StringBuilder sb = new StringBuilder(); 93 sb.append(driverInfo.nativeLibraryDir) 94 .append(File.pathSeparator); 95 sb.append(driverInfo.sourceDir) 96 .append("!/lib/") 97 .append(abi); 98 String paths = sb.toString(); 99 100 if (DEBUG) Log.v(TAG, "gfx driver package libs: " + paths); 101 setDriverPath(paths); 102 } 103 104 private static String chooseAbi(ApplicationInfo ai) { 105 String isa = VMRuntime.getCurrentInstructionSet(); 106 if (ai.primaryCpuAbi != null && 107 isa.equals(VMRuntime.getInstructionSet(ai.primaryCpuAbi))) { 108 return ai.primaryCpuAbi; 109 } 110 if (ai.secondaryCpuAbi != null && 111 isa.equals(VMRuntime.getInstructionSet(ai.secondaryCpuAbi))) { 112 return ai.secondaryCpuAbi; 113 } 114 return null; 115 } 116 117 private static native void setDriverPath(String path); 118 119 } 120