diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 6a2b9aa22928e..5cfcac33050e0 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -62,6 +62,7 @@ import android.os.Bundle; import android.os.Debug; import android.os.DropBoxManager; import android.os.Environment; +import android.os.GraphicsEnvironment; import android.os.Handler; import android.os.IBinder; import android.os.LocaleList; @@ -5012,7 +5013,7 @@ public final class ActivityThread { WindowManagerGlobal.getInstance().trimMemory(level); } - private void setupGraphicsSupport(LoadedApk info, File cacheDir) { + private void setupGraphicsSupport(Context context, File cacheDir) { if (Process.isIsolated()) { // Isolated processes aren't going to do UI. return; @@ -5025,6 +5026,7 @@ public final class ActivityThread { if (packages != null) { ThreadedRenderer.setupDiskCache(cacheDir); RenderScriptCacheDir.setupDiskCache(cacheDir); + GraphicsEnvironment.setupGraphicsEnvironment(context); } } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -5312,7 +5314,7 @@ public final class ActivityThread { final Context deviceContext = appContext.createDeviceProtectedStorageContext(); final File codeCacheDir = deviceContext.getCodeCacheDir(); if (codeCacheDir != null) { - setupGraphicsSupport(data.info, codeCacheDir); + setupGraphicsSupport(appContext, codeCacheDir); } else { Log.e(TAG, "Unable to setupGraphicsSupport due to missing code-cache directory"); } diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java new file mode 100644 index 0000000000000..4b130ed1adc8a --- /dev/null +++ b/core/java/android/os/GraphicsEnvironment.java @@ -0,0 +1,95 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.SystemProperties; +import android.util.Log; + +import dalvik.system.VMRuntime; + +import java.io.File; + +/** @hide */ +public final class GraphicsEnvironment { + + private static final boolean DEBUG = false; + private static final String TAG = "GraphicsEnvironment"; + private static final String PROPERTY_GFX_DRIVER = "ro.gfx.driver.0"; + + public static void setupGraphicsEnvironment(Context context) { + String driverPackageName = SystemProperties.get(PROPERTY_GFX_DRIVER); + if (driverPackageName == null || driverPackageName.isEmpty()) { + return; + } + // To minimize risk of driver updates crippling the device beyond user repair, never use an + // updated driver for privileged or non-updated system apps. Presumably pre-installed apps + // were tested thoroughly with the pre-installed driver. + ApplicationInfo ai = context.getApplicationInfo(); + if (ai.isPrivilegedApp() || (ai.isSystemApp() && !ai.isUpdatedSystemApp())) { + if (DEBUG) Log.v(TAG, "ignoring driver package for privileged/non-updated system app"); + return; + } + ApplicationInfo driverInfo; + try { + driverInfo = context.getPackageManager().getApplicationInfo(driverPackageName, + PackageManager.MATCH_SYSTEM_ONLY); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "driver package '" + driverPackageName + "' not installed"); + return; + } + String abi = chooseAbi(driverInfo); + if (abi == null) { + if (DEBUG) { + // This is the normal case for the pre-installed empty driver package, don't spam + if (driverInfo.isUpdatedSystemApp()) { + Log.w(TAG, "updated driver package has no compatible native libraries"); + } + } + return; + } + + StringBuilder sb = new StringBuilder(); + sb.append(driverInfo.nativeLibraryDir) + .append(File.pathSeparator); + sb.append(driverInfo.sourceDir) + .append("!/lib/") + .append(abi); + String paths = sb.toString(); + + if (DEBUG) Log.v(TAG, "gfx driver package libs: " + paths); + setDriverPath(paths); + } + + private static String chooseAbi(ApplicationInfo ai) { + String isa = VMRuntime.getCurrentInstructionSet(); + if (ai.primaryCpuAbi != null && + isa.equals(VMRuntime.getInstructionSet(ai.primaryCpuAbi))) { + return ai.primaryCpuAbi; + } + if (ai.secondaryCpuAbi != null && + isa.equals(VMRuntime.getInstructionSet(ai.secondaryCpuAbi))) { + return ai.secondaryCpuAbi; + } + return null; + } + + private static native void setDriverPath(String path); + +} diff --git a/core/jni/Android.mk b/core/jni/Android.mk index dd66b24a6b2f9..6dabc77b0e58e 100644 --- a/core/jni/Android.mk +++ b/core/jni/Android.mk @@ -80,6 +80,7 @@ LOCAL_SRC_FILES:= \ android_text_AndroidBidi.cpp \ android_text_StaticLayout.cpp \ android_os_Debug.cpp \ + android_os_GraphicsEnvironment.cpp \ android_os_MemoryFile.cpp \ android_os_MessageQueue.cpp \ android_os_Parcel.cpp \ diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp index 315887d954e51..174d382c01b3c 100644 --- a/core/jni/AndroidRuntime.cpp +++ b/core/jni/AndroidRuntime.cpp @@ -156,6 +156,7 @@ extern int register_android_database_SQLiteGlobal(JNIEnv* env); extern int register_android_database_SQLiteDebug(JNIEnv* env); extern int register_android_nio_utils(JNIEnv* env); extern int register_android_os_Debug(JNIEnv* env); +extern int register_android_os_GraphicsEnvironment(JNIEnv* env); extern int register_android_os_MessageQueue(JNIEnv* env); extern int register_android_os_Parcel(JNIEnv* env); extern int register_android_os_SELinux(JNIEnv* env); @@ -1348,6 +1349,7 @@ static const RegJNIRec gRegJNI[] = { REG_JNI(register_android_database_SQLiteDebug), REG_JNI(register_android_os_Debug), REG_JNI(register_android_os_FileObserver), + REG_JNI(register_android_os_GraphicsEnvironment), REG_JNI(register_android_os_MessageQueue), REG_JNI(register_android_os_SELinux), REG_JNI(register_android_os_Trace), diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp new file mode 100644 index 0000000000000..905a85adc5510 --- /dev/null +++ b/core/jni/android_os_GraphicsEnvironment.cpp @@ -0,0 +1,44 @@ +/* + * Copyright 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "GraphicsEnvironment" + +#include +#include +#include "core_jni_helpers.h" + +namespace { + +void setDriverPath(JNIEnv* env, jobject clazz, jstring path) { + ScopedUtfChars pathChars(env, path); + android::GraphicsEnv::getInstance().setDriverPath(pathChars.c_str()); +} + +const JNINativeMethod g_methods[] = { + { "setDriverPath", "(Ljava/lang/String;)V", reinterpret_cast(setDriverPath) }, +}; + +const char* const kGraphicsEnvironmentName = "android/os/GraphicsEnvironment"; + +} // anonymous namespace + +namespace android { + +int register_android_os_GraphicsEnvironment(JNIEnv* env) { + return RegisterMethodsOrDie(env, kGraphicsEnvironmentName, g_methods, NELEM(g_methods)); +} + +} // namespace android