Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eb1c5a4c authored by Peiyong Lin's avatar Peiyong Lin
Browse files

Allow to load implicit layer from /vendor/app.

Currently when loading implicit layers from apks, NativeLoaderNamespace
doesn't allow to dlopen the binaries if they come from apks from
/vendor/app. Implicit layers ship within /vendor/app should work like
other implicit layers. This patch extracts the construction of library
paths of the implicit layers and includes those paths when
NativeLoaderNamespace is created as the part of the permitted library
paths.

Bug: b/157832445
Test: atest android.gputools.cts.CtsRootlessGpuDebugHostTest
Test: setup debug layer and use adb logcat to check vulkan loader output
Change-Id: Ie2ca989bcab890578b5aa540d07f2aee2a0182bd
parent 0d07c9ac
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -7388,6 +7388,10 @@ public final class ActivityThread extends ClientTransactionHandler {
        }
    }

    public Bundle getCoreSettings() {
        return mCoreSettings;
    }

    public int getIntCoreSetting(String key, int defaultValue) {
        synchronized (mResourcesManager) {
            if (mCoreSettings != null) {
@@ -7397,6 +7401,18 @@ public final class ActivityThread extends ClientTransactionHandler {
        }
    }

    /**
     * Get the string value of the given key from core settings.
     */
    public String getStringCoreSetting(String key, String defaultValue) {
        synchronized (mResourcesManager) {
            if (mCoreSettings != null) {
                return mCoreSettings.getString(key, defaultValue);
            }
            return defaultValue;
        }
    }

    float getFloatCoreSetting(String key, float defaultValue) {
        synchronized (mResourcesManager) {
            if (mCoreSettings != null) {
+28 −0
Original line number Diff line number Diff line
@@ -38,6 +38,7 @@ import android.content.res.Resources;
import android.os.Build;
import android.os.Bundle;
import android.os.FileUtils;
import android.os.GraphicsEnvironment;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
@@ -46,6 +47,7 @@ import android.os.StrictMode;
import android.os.SystemProperties;
import android.os.Trace;
import android.os.UserHandle;
import android.provider.Settings;
import android.security.net.config.NetworkSecurityConfigProvider;
import android.sysprop.VndkProperties;
import android.text.TextUtils;
@@ -824,6 +826,32 @@ public final class LoadedApk {

        final String librarySearchPath = TextUtils.join(File.pathSeparator, libPaths);

        if (mActivityThread != null) {
            final String gpuDebugApp = mActivityThread.getStringCoreSetting(
                    Settings.Global.GPU_DEBUG_APP, "");
            if (!gpuDebugApp.isEmpty() && mPackageName.equals(gpuDebugApp)) {

                // The current application is used to debug, attempt to get the debug layers.
                try {
                    // Get the ApplicationInfo from PackageManager so that metadata fields present.
                    final ApplicationInfo ai = ActivityThread.getPackageManager()
                            .getApplicationInfo(mPackageName, PackageManager.GET_META_DATA,
                                    UserHandle.myUserId());
                    final String debugLayerPath = GraphicsEnvironment.getInstance()
                            .getDebugLayerPathsFromSettings(mActivityThread.getCoreSettings(),
                                    ActivityThread.getPackageManager(), mPackageName, ai);
                    if (debugLayerPath != null) {
                        libraryPermittedPath += File.pathSeparator + debugLayerPath;
                    }
                } catch (RemoteException e) {
                    // Unlikely to fail for applications, but in case of failure, something is wrong
                    // inside the system server, hence just skip.
                    Slog.e(ActivityThread.TAG,
                            "RemoteException when fetching debug layer paths for: " + mPackageName);
                }
            }
        }

        // If we're not asked to include code, we construct a classloader that has
        // no code path included. We still need to set up the library search paths
        // and permitted path because NativeActivity relies on it (it attempts to
+90 −76
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageManager;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
@@ -93,8 +94,8 @@ public class GraphicsEnvironment {
    private static final int GAME_DRIVER_GLOBAL_OPT_IN_OFF = 3;

    private ClassLoader mClassLoader;
    private String mLayerPath;
    private String mDebugLayerPath;
    private String mLibrarySearchPaths;
    private String mLibraryPermittedPaths;

    /**
     * Set up GraphicsEnvironment
@@ -185,99 +186,116 @@ public class GraphicsEnvironment {
    }

    /**
     * Store the layer paths available to the loader.
     * Store the class loader for namespace lookup later.
     */
    public void setLayerPaths(ClassLoader classLoader,
                              String layerPath,
                              String debugLayerPath) {
                              String searchPaths,
                              String permittedPaths) {
        // We have to store these in the class because they are set up before we
        // have access to the Context to properly set up GraphicsEnvironment
        mClassLoader = classLoader;
        mLayerPath = layerPath;
        mDebugLayerPath = debugLayerPath;
        mLibrarySearchPaths = searchPaths;
        mLibraryPermittedPaths = permittedPaths;
    }

    /**
     * Returns the debug layer paths from settings.
     * Returns null if:
     *     1) The application process is not debuggable or layer injection metadata flag is not
     *        true; Or
     *     2) ENABLE_GPU_DEBUG_LAYERS is not true; Or
     *     3) Package name is not equal to GPU_DEBUG_APP.
     */
    public String getDebugLayerPathsFromSettings(
            Bundle coreSettings, IPackageManager pm, String packageName,
            ApplicationInfo ai) {
        if (!debugLayerEnabled(coreSettings, packageName, ai)) {
            return null;
        }
        Log.i(TAG, "GPU debug layers enabled for " + packageName);
        String debugLayerPaths = "";

        // Grab all debug layer apps and add to paths.
        final String gpuDebugLayerApps =
                coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP, "");
        if (!gpuDebugLayerApps.isEmpty()) {
            Log.i(TAG, "GPU debug layer apps: " + gpuDebugLayerApps);
            // If a colon is present, treat this as multiple apps, so Vulkan and GLES
            // layer apps can be provided at the same time.
            final String[] layerApps = gpuDebugLayerApps.split(":");
            for (int i = 0; i < layerApps.length; i++) {
                String paths = getDebugLayerAppPaths(pm, layerApps[i]);
                if (!paths.isEmpty()) {
                    // Append the path so files placed in the app's base directory will
                    // override the external path
                    debugLayerPaths += paths + File.pathSeparator;
                }
            }
        }
        return debugLayerPaths;
    }

    /**
     * Return the debug layer app's on-disk and in-APK lib directories
     */
    private static String getDebugLayerAppPaths(PackageManager pm, String app) {
    private static String getDebugLayerAppPaths(IPackageManager pm, String packageName) {
        final ApplicationInfo appInfo;
        try {
            appInfo = pm.getApplicationInfo(app, PackageManager.MATCH_ALL);
        } catch (PackageManager.NameNotFoundException e) {
            Log.w(TAG, "Debug layer app '" + app + "' not installed");

            return null;
            appInfo = pm.getApplicationInfo(packageName, PackageManager.MATCH_ALL,
                    UserHandle.myUserId());
        } catch (RemoteException e) {
            return "";
        }
        if (appInfo == null) {
            Log.w(TAG, "Debug layer app '" + packageName + "' not installed");
        }

        final String abi = chooseAbi(appInfo);

        final StringBuilder sb = new StringBuilder();
        sb.append(appInfo.nativeLibraryDir)
            .append(File.pathSeparator);
        sb.append(appInfo.sourceDir)
            .append(File.pathSeparator)
            .append(appInfo.sourceDir)
            .append("!/lib/")
            .append(abi);
        final String paths = sb.toString();

        if (DEBUG) Log.v(TAG, "Debug layer app libs: " + paths);

        return paths;
    }

    /**
     * Set up layer search paths for all apps
     * If debuggable, check for additional debug settings
     */
    private void setupGpuLayers(
            Context context, Bundle coreSettings, PackageManager pm, String packageName,
            ApplicationInfo ai) {
        String layerPaths = "";

    private boolean debugLayerEnabled(Bundle coreSettings, String packageName, ApplicationInfo ai) {
        // Only enable additional debug functionality if the following conditions are met:
        // 1. App is debuggable or device is rooted or layer injection metadata flag is true
        // 2. ENABLE_GPU_DEBUG_LAYERS is true
        // 3. Package name is equal to GPU_DEBUG_APP

        if (isDebuggable() || canInjectLayers(ai)) {

        if (!isDebuggable() && !canInjectLayers(ai)) {
            return false;
        }
        final int enable = coreSettings.getInt(Settings.Global.ENABLE_GPU_DEBUG_LAYERS, 0);

            if (enable != 0) {

                final String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP);

                if ((gpuDebugApp != null && packageName != null)
                        && (!gpuDebugApp.isEmpty() && !packageName.isEmpty())
                        && gpuDebugApp.equals(packageName)) {
                    Log.i(TAG, "GPU debug layers enabled for " + packageName);

                    // Prepend the debug layer path as a searchable path.
                    // This will ensure debug layers added will take precedence over
                    // the layers specified by the app.
                    layerPaths = mDebugLayerPath + ":";

                    // If there is a debug layer app specified, add its path.
                    final String gpuDebugLayerApp =
                            coreSettings.getString(Settings.Global.GPU_DEBUG_LAYER_APP);

                    if (gpuDebugLayerApp != null && !gpuDebugLayerApp.isEmpty()) {
                        Log.i(TAG, "GPU debug layer app: " + gpuDebugLayerApp);
                        // If a colon is present, treat this as multiple apps, so Vulkan and GLES
                        // layer apps can be provided at the same time.
                        String[] layerApps = gpuDebugLayerApp.split(":");
                        for (int i = 0; i < layerApps.length; i++) {
                            String paths = getDebugLayerAppPaths(pm, layerApps[i]);
                            if (paths != null) {
                                // Append the path so files placed in the app's base directory will
                                // override the external path
                                layerPaths += paths + ":";
        if (enable == 0) {
            return false;
        }
        final String gpuDebugApp = coreSettings.getString(Settings.Global.GPU_DEBUG_APP, "");
        if (packageName == null
                || (gpuDebugApp.isEmpty() || packageName.isEmpty())
                || !gpuDebugApp.equals(packageName)) {
            return false;
        }
        return true;
    }

                    final String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
    /**
     * Set up layer search paths for all apps
     */
    private void setupGpuLayers(
            Context context, Bundle coreSettings, PackageManager pm, String packageName,
            ApplicationInfo ai) {
        final boolean enabled = debugLayerEnabled(coreSettings, packageName, ai);
        String layerPaths = "";
        if (enabled) {
            layerPaths = mLibraryPermittedPaths;

            final String layers = coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS);
            Log.i(TAG, "Vulkan debug layer list: " + layers);
            if (layers != null && !layers.isEmpty()) {
                setDebugLayers(layers);
@@ -285,18 +303,14 @@ public class GraphicsEnvironment {

            final String layersGLES =
                    coreSettings.getString(Settings.Global.GPU_DEBUG_LAYERS_GLES);

            Log.i(TAG, "GLES debug layer list: " + layersGLES);
            if (layersGLES != null && !layersGLES.isEmpty()) {
                setDebugLayersGLES(layersGLES);
            }
        }
            }
        }

        // Include the app's lib directory in all cases
        layerPaths += mLayerPath;

        layerPaths += mLibrarySearchPaths;
        setLayerPaths(mClassLoader, layerPaths);
    }