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

Commit 5e21eb35 authored by Yiwei Zhang's avatar Yiwei Zhang
Browse files

GL: unload system driver if needed

Both ANGLE and Game Driver originally require the GL driver to be not loaded
before the App launches. However, extra memory overhead from loading GL driver
in each process requires us to enable gl driver preloading in Zygote again.

So this CL adds the logic to unload the system driver if the App chooses to use
ANGLE or Game Driver. As long as nobody is using GL api in Zygote to create any
context, the unloading at App launch time should be safe.

eglGetDisplay will always ask the driver for the display handle after this
change, otherwise it will still use the cached display handle even we unload
the system driver and load the ANGLE or Game Driver. This means we no longer
cache it because eglGetDisplay is rarely called and trivial for the driver.

Bug: 134526352
Test: build, flash and boot. Then manually test with ANGLE and Game Driver.
Change-Id: I7c068ce9f630347a5d94823bbe6cfbac0f280e91
parent 0683fe79
Loading
Loading
Loading
Loading
+62 −49
Original line number Diff line number Diff line
@@ -534,60 +534,73 @@ void GraphicsEnv::setDebugLayersGLES(const std::string layers) {
    mDebugLayersGLES = layers;
}

android_namespace_t* GraphicsEnv::getDriverNamespace() {
    static std::once_flag once;
    std::call_once(once, [this]() {
        if (mDriverPath.empty()) return;

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

        mDriverNamespace = android_create_namespace("gfx driver",
                                                    mDriverPath.c_str(), // ld_library_path
                                                    mDriverPath.c_str(), // default_library_path
                                                    ANDROID_NAMESPACE_TYPE_ISOLATED,
                                                    nullptr, // permitted_when_isolated_path
                                                    nullptr);

// Return true if all the required libraries from vndk and sphal namespace are
// linked to the Game Driver namespace correctly.
bool GraphicsEnv::linkDriverNamespaceLocked(android_namespace_t* vndkNamespace) {
    const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK);
    if (llndkLibraries.empty()) {
            mDriverNamespace = nullptr;
            return;
        return false;
    }
    if (!android_link_namespaces(mDriverNamespace, nullptr, llndkLibraries.c_str())) {
        ALOGE("Failed to link default namespace[%s]", dlerror());
            mDriverNamespace = nullptr;
            return;
        return false;
    }

    const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP);
    if (vndkspLibraries.empty()) {
            mDriverNamespace = nullptr;
            return;
        return false;
    }
    if (!android_link_namespaces(mDriverNamespace, vndkNamespace, vndkspLibraries.c_str())) {
        ALOGE("Failed to link vndk namespace[%s]", dlerror());
            mDriverNamespace = nullptr;
            return;
        return false;
    }

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

    // Make additional libraries in sphal to be accessible
    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());
            mDriverNamespace = nullptr;
            return;
        return false;
    }

    if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) {
        ALOGE("Failed to link sphal namespace[%s]", dlerror());
        return false;
    }

    return true;
}

android_namespace_t* GraphicsEnv::getDriverNamespace() {
    std::lock_guard<std::mutex> lock(mNamespaceMutex);

    if (mDriverNamespace) {
        return mDriverNamespace;
    }

    if (mDriverPath.empty()) {
        return nullptr;
    }

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

    mDriverNamespace = android_create_namespace("gfx driver",
                                                mDriverPath.c_str(), // ld_library_path
                                                mDriverPath.c_str(), // default_library_path
                                                ANDROID_NAMESPACE_TYPE_ISOLATED,
                                                nullptr, // permitted_when_isolated_path
                                                nullptr);

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

    return mDriverNamespace;
}
+1 −0
Original line number Diff line number Diff line
@@ -129,6 +129,7 @@ private:
    void* loadLibrary(std::string name);
    bool checkAngleRules(void* so);
    void updateUseAngle();
    bool linkDriverNamespaceLocked(android_namespace_t* vndkNamespace);

    GraphicsEnv() = default;
    std::string mDriverPath;
+85 −3
Original line number Diff line number Diff line
@@ -84,6 +84,11 @@ static void* do_android_load_sphal_library(const char* path, int mode) {
    return android_load_sphal_library(path, mode);
}

static int do_android_unload_sphal_library(void* dso) {
    ATRACE_CALL();
    return android_unload_sphal_library(dso);
}

Loader::driver_t::driver_t(void* gles)
{
    dso[0] = gles;
@@ -180,11 +185,81 @@ static const char* HAL_SUBNAME_KEY_PROPERTIES[2] = {
    "ro.board.platform",
};

static bool should_unload_system_driver(egl_connection_t* cnx) {
    // Return false if the system driver has been unloaded once.
    if (cnx->systemDriverUnloaded) {
        return false;
    }

    // Return true if Angle namespace is set.
    android_namespace_t* ns = android::GraphicsEnv::getInstance().getAngleNamespace();
    if (ns) {
        return true;
    }

#ifndef __ANDROID_VNDK__
    // Return true if updated driver namespace is set.
    ns = android::GraphicsEnv::getInstance().getDriverNamespace();
    if (ns) {
        return true;
    }
#endif

    return false;
}

static void uninit_api(char const* const* api, __eglMustCastToProperFunctionPointerType* curr) {
    while (*api) {
        *curr++ = nullptr;
        api++;
    }
}

void Loader::unload_system_driver(egl_connection_t* cnx) {
    ATRACE_CALL();

    uninit_api(gl_names,
               (__eglMustCastToProperFunctionPointerType*)&cnx
                       ->hooks[egl_connection_t::GLESv2_INDEX]
                       ->gl);
    uninit_api(gl_names,
               (__eglMustCastToProperFunctionPointerType*)&cnx
                       ->hooks[egl_connection_t::GLESv1_INDEX]
                       ->gl);
    uninit_api(egl_names, (__eglMustCastToProperFunctionPointerType*)&cnx->egl);

    if (cnx->dso) {
        ALOGD("Unload system gl driver.");
        driver_t* hnd = (driver_t*)cnx->dso;
        if (hnd->dso[2]) {
            do_android_unload_sphal_library(hnd->dso[2]);
        }
        if (hnd->dso[1]) {
            do_android_unload_sphal_library(hnd->dso[1]);
        }
        if (hnd->dso[0]) {
            do_android_unload_sphal_library(hnd->dso[0]);
        }
        cnx->dso = nullptr;
    }

    cnx->systemDriverUnloaded = true;
}

void* Loader::open(egl_connection_t* cnx)
{
    ATRACE_CALL();
    const nsecs_t openTime = systemTime();

    if (should_unload_system_driver(cnx)) {
        unload_system_driver(cnx);
    }

    // If a driver has been loaded, return the driver directly.
    if (cnx->dso) {
        return cnx->dso;
    }

    setEmulatorGlesValue();

    // Check if we should use ANGLE early, so loading each driver doesn't require repeated queries.
@@ -244,9 +319,15 @@ void* Loader::open(egl_connection_t* cnx)
                        "couldn't find an OpenGL ES implementation, make sure you set %s or %s",
                        HAL_SUBNAME_KEY_PROPERTIES[0], HAL_SUBNAME_KEY_PROPERTIES[1]);

    if (!cnx->libEgl) {
        cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so");
    cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
    }
    if (!cnx->libGles1) {
        cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
    }
    if (!cnx->libGles2) {
        cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
    }

    if (!cnx->libEgl || !cnx->libGles2 || !cnx->libGles1) {
        android::GraphicsEnv::getInstance().setDriverLoaded(android::GraphicsEnv::Api::API_GL,
@@ -584,6 +665,7 @@ Loader::driver_t* Loader::attempt_to_load_updated_driver(egl_connection_t* cnx)
        return nullptr;
    }

    ALOGD("Load updated gl driver.");
    android::GraphicsEnv::getInstance().setDriverToLoad(android::GraphicsEnv::Driver::GL_UPDATED);
    driver_t* hnd = nullptr;
    void* dso = load_updated_driver("GLES", ns);
+1 −0
Original line number Diff line number Diff line
@@ -58,6 +58,7 @@ private:
    driver_t* attempt_to_load_angle(egl_connection_t* cnx);
    driver_t* attempt_to_load_updated_driver(egl_connection_t* cnx);
    driver_t* attempt_to_load_system_driver(egl_connection_t* cnx, const char* suffix, const bool exact);
    void unload_system_driver(egl_connection_t* cnx);
    void initialize_api(void* dso, egl_connection_t* cnx, uint32_t mask);

    static __attribute__((noinline))
+3 −7
Original line number Diff line number Diff line
@@ -187,13 +187,9 @@ static EGLBoolean egl_init_drivers_locked() {

    // dynamically load our EGL implementation
    egl_connection_t* cnx = &gEGLImpl;
    if (cnx->dso == nullptr) {
        cnx->hooks[egl_connection_t::GLESv1_INDEX] =
                &gHooks[egl_connection_t::GLESv1_INDEX];
        cnx->hooks[egl_connection_t::GLESv2_INDEX] =
                &gHooks[egl_connection_t::GLESv2_INDEX];
    cnx->hooks[egl_connection_t::GLESv1_INDEX] = &gHooks[egl_connection_t::GLESv1_INDEX];
    cnx->hooks[egl_connection_t::GLESv2_INDEX] = &gHooks[egl_connection_t::GLESv2_INDEX];
    cnx->dso = loader.open(cnx);
    }

    // Check to see if any layers are enabled and route functions through them
    if (cnx->dso) {
Loading