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

Commit 9b8ec2f0 authored by Peiyong Lin's avatar Peiyong Lin
Browse files

Allow per-app opt in to use system ANGLE.

Previously the per-app opt in only works for ANGLE apk, this patch
refactors the logic to allow per-app opt in to work for system ANGLE.
This patch checks whether system ANGLE is supported and if it presents,
uses it if the ANGLE apk setup fails.

With this patch, the per-app opt in will function this way:

1) When full ANGLE apk is installed
Regardless of whether system ANGLE is present, the "angle" option will
use ANGLE apk, the "native" option will switch to native GLES drivers
specified by ro.hardware.egl, the "default" option will use whatever the
default graphics driver is loaded.

2) When full ANGLE apk is not installed and system ANGLE is present
The "angle" option will use system ANGLE, the "native" option will
switch to native GLES drivers specified by ro.hardware.egl, the
"default" option will use whatever the default graphics driver is
loaded.

3) When full ANGLE apk is not installed and system ANGLE doesn't exist
The per-app option will not function at all.

To Properly load ANGLE, the namespace of system ANGLE should be
inherited from sphal namespace so that search paths and libraries
linkage are properly constructed.

Minor: clean up unused and unnecessary variables.

Bug: b/283858001
Test: test with camera
Test: atest CtsAngleIntegrationHostTestCases
Change-Id: I2c9d4e1747796d2b0ae58c4456b781b9940fbb26
parent d136af5b
Loading
Loading
Loading
Loading
+59 −46
Original line number Diff line number Diff line
@@ -399,45 +399,28 @@ bool GraphicsEnv::shouldUseAngle() {
        return false;
    }

    return (mShouldUseAngle == YES) ? true : false;
    return mShouldUseAngle;
}

void GraphicsEnv::updateShouldUseAngle() {
    const char* ANGLE_PREFER_ANGLE = "angle";
    const char* ANGLE_PREFER_NATIVE = "native";

    mShouldUseAngle = NO;
    if (mAngleDeveloperOptIn == ANGLE_PREFER_ANGLE) {
        ALOGV("User set \"Developer Options\" to force the use of ANGLE");
        mShouldUseAngle = YES;
    } else if (mAngleDeveloperOptIn == ANGLE_PREFER_NATIVE) {
        ALOGV("User set \"Developer Options\" to force the use of Native");
    } else {
        ALOGV("User set invalid \"Developer Options\": '%s'", mAngleDeveloperOptIn.c_str());
    }
}

void GraphicsEnv::setAngleInfo(const std::string& path, const std::string& packageName,
                               const std::string& developerOptIn,
void GraphicsEnv::setAngleInfo(const std::string& path, const bool useSystemAngle,
                               const std::string& packageName,
                               const std::vector<std::string> eglFeatures) {
    if (mShouldUseAngle != UNKNOWN) {
        // We've already figured out an answer for this app, so just return.
        ALOGV("Already evaluated the rules file for '%s': use ANGLE = %s", packageName.c_str(),
              (mShouldUseAngle == YES) ? "true" : "false");
    if (mShouldUseAngle) {
        // ANGLE is already set up for this application process, even if the application
        // needs to switch from apk to system or vice versa, the application process must
        // be killed and relaunch so that the loader can properly load ANGLE again.
        // The architecture does not support runtime switch between drivers, so just return.
        ALOGE("ANGLE is already set for %s", packageName.c_str());
        return;
    }

    mAngleEglFeatures = std::move(eglFeatures);

    ALOGV("setting ANGLE path to '%s'", path.c_str());
    mAnglePath = path;
    mAnglePath = std::move(path);
    ALOGV("setting app package name to '%s'", packageName.c_str());
    mPackageName = packageName;
    ALOGV("setting ANGLE application opt-in to '%s'", developerOptIn.c_str());
    mAngleDeveloperOptIn = developerOptIn;

    // Update the current status of whether we should use ANGLE or not
    updateShouldUseAngle();
    mPackageName = std::move(packageName);
    mShouldUseAngle = true;
    mUseSystemAngle = useSystemAngle;
}

void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace,
@@ -484,13 +467,15 @@ void GraphicsEnv::setDebugLayersGLES(const std::string& layers) {
}

// Return true if all the required libraries from vndk and sphal namespace are
// linked to the updatable gfx driver namespace correctly.
bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace) {
// linked to the driver namespace correctly.
bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* destNamespace,
                                            android_namespace_t* vndkNamespace,
                                            const std::string& sharedSphalLibraries) {
    const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK);
    if (llndkLibraries.empty()) {
        return false;
    }
    if (!android_link_namespaces(mDriverNamespace, nullptr, llndkLibraries.c_str())) {
    if (!android_link_namespaces(destNamespace, nullptr, llndkLibraries.c_str())) {
        ALOGE("Failed to link default namespace[%s]", dlerror());
        return false;
    }
@@ -499,12 +484,12 @@ bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace)
    if (vndkspLibraries.empty()) {
        return false;
    }
    if (!android_link_namespaces(mDriverNamespace, vndkNamespace, vndkspLibraries.c_str())) {
    if (!android_link_namespaces(destNamespace, vndkNamespace, vndkspLibraries.c_str())) {
        ALOGE("Failed to link vndk namespace[%s]", dlerror());
        return false;
    }

    if (mSphalLibraries.empty()) {
    if (sharedSphalLibraries.empty()) {
        return true;
    }

@@ -512,11 +497,11 @@ bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace)
    auto sphalNamespace = android_get_exported_namespace("sphal");
    if (!sphalNamespace) {
        ALOGE("Depend on these libraries[%s] in sphal, but failed to get sphal namespace",
              mSphalLibraries.c_str());
              sharedSphalLibraries.c_str());
        return false;
    }

    if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) {
    if (!android_link_namespaces(destNamespace, sphalNamespace, sharedSphalLibraries.c_str())) {
        ALOGE("Failed to link sphal namespace[%s]", dlerror());
        return false;
    }
@@ -568,7 +553,7 @@ android_namespace_t* GraphicsEnv::getDriverNamespace() {
                                                nullptr, // permitted_when_isolated_path
                                                nullptr);

    if (!linkDriverNamespaceLocked(vndkNamespace)) {
    if (!linkDriverNamespaceLocked(mDriverNamespace, vndkNamespace, mSphalLibraries)) {
        mDriverNamespace = nullptr;
    }

@@ -586,20 +571,48 @@ android_namespace_t* GraphicsEnv::getAngleNamespace() {
        return mAngleNamespace;
    }

    if (mAnglePath.empty()) {
        ALOGV("mAnglePath is empty, not creating ANGLE namespace");
    if (mAnglePath.empty() && !mUseSystemAngle) {
        ALOGV("mAnglePath is empty and not using system ANGLE, abort creating ANGLE namespace");
        return nullptr;
    }

    mAngleNamespace = android_create_namespace("ANGLE",
                                               nullptr,            // ld_library_path
                                               mAnglePath.c_str(), // default_library_path
    // Construct the search paths for system ANGLE.
    const char* const defaultLibraryPaths =
#if defined(__LP64__)
            "/vendor/lib64/egl:/system/lib64/egl";
#else
            "/vendor/lib/egl:/system/lib/egl";
#endif

    // If the application process will run on top of system ANGLE, construct the namespace
    // with sphal namespace being the parent namespace so that search paths and libraries
    // are properly inherited.
    mAngleNamespace =
            android_create_namespace("ANGLE",
                                     mUseSystemAngle ? defaultLibraryPaths
                                                     : mAnglePath.c_str(), // ld_library_path
                                     mUseSystemAngle ? defaultLibraryPaths
                                                     : mAnglePath.c_str(), // default_library_path
                                     ANDROID_NAMESPACE_TYPE_SHARED_ISOLATED,
                                     nullptr, // permitted_when_isolated_path
                                               nullptr);
                                     mUseSystemAngle ? android_get_exported_namespace("sphal")
                                                     : nullptr); // parent

    ALOGD_IF(!mAngleNamespace, "Could not create ANGLE namespace from default");

    if (!mUseSystemAngle) {
        return mAngleNamespace;
    }

    auto vndkNamespace = android_get_exported_namespace("vndk");
    if (!vndkNamespace) {
        return nullptr;
    }

    if (!linkDriverNamespaceLocked(mAngleNamespace, vndkNamespace, "")) {
        mAngleNamespace = nullptr;
    }

    return mAngleNamespace;
}

+14 −11
Original line number Diff line number Diff line
@@ -29,6 +29,11 @@ namespace android {

struct NativeLoaderNamespace;

// The GraphicsEnv is a singleton per application process and is used to properly set up the
// graphics drivers for the application process during application starts. The architecture of
// the graphics driver loader does not support runtime switch and only supports switch to different
// graphics drivers when application process launches and hence the only way to switch to different
// graphics drivers is to completely kill the application process and relaunch the application.
class GraphicsEnv {
public:
    static GraphicsEnv& getInstance();
@@ -103,8 +108,8 @@ public:
    // (libraries must be stored uncompressed and page aligned); such elements
    // in the search path must have a '!' after the zip filename, e.g.
    //     /system/app/ANGLEPrebuilt/ANGLEPrebuilt.apk!/lib/arm64-v8a
    void setAngleInfo(const std::string& path, const std::string& packageName,
                      const std::string& devOptIn, const std::vector<std::string> eglFeatures);
    void setAngleInfo(const std::string& path, const bool useSystemAngle,
                      const std::string& packageName, const std::vector<std::string> eglFeatures);
    // Get the ANGLE driver namespace.
    android_namespace_t* getAngleNamespace();
    // Get the app package name.
@@ -132,12 +137,10 @@ public:
    const std::string& getDebugLayersGLES();

private:
    enum UseAngle { UNKNOWN, YES, NO };

    // Update whether ANGLE should be used.
    void updateShouldUseAngle();
    // Link updatable driver namespace with llndk and vndk-sp libs.
    bool linkDriverNamespaceLocked(android_namespace_t* vndkNamespace);
    bool linkDriverNamespaceLocked(android_namespace_t* destNamespace,
                                   android_namespace_t* vndkNamespace,
                                   const std::string& sharedSphalLibraries);
    // Check whether this process is ready to send stats.
    bool readyToSendGpuStatsLocked();
    // Send the initial complete GpuStats to GpuService.
@@ -165,12 +168,12 @@ private:
    std::string mAnglePath;
    // App's package name.
    std::string mPackageName;
    // ANGLE developer opt in status.
    std::string mAngleDeveloperOptIn;
    // ANGLE EGL features;
    std::vector<std::string> mAngleEglFeatures;
    // Use ANGLE flag.
    UseAngle mShouldUseAngle = UNKNOWN;
    // Whether ANGLE should be used.
    bool mShouldUseAngle = false;
    // Whether loader should load system ANGLE.
    bool mUseSystemAngle = false;
    // ANGLE namespace.
    android_namespace_t* mAngleNamespace = nullptr;