Merge "GL: unload system driver if needed" into qt-dev
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 407f77d..1c5fa52 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -534,60 +534,73 @@
     mDebugLayersGLES = layers;
 }
 
+// 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()) {
+        return false;
+    }
+    if (!android_link_namespaces(mDriverNamespace, nullptr, llndkLibraries.c_str())) {
+        ALOGE("Failed to link default namespace[%s]", dlerror());
+        return false;
+    }
+
+    const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP);
+    if (vndkspLibraries.empty()) {
+        return false;
+    }
+    if (!android_link_namespaces(mDriverNamespace, vndkNamespace, vndkspLibraries.c_str())) {
+        ALOGE("Failed to link vndk namespace[%s]", dlerror());
+        return false;
+    }
+
+    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());
+        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() {
-    static std::once_flag once;
-    std::call_once(once, [this]() {
-        if (mDriverPath.empty()) return;
+    std::lock_guard<std::mutex> lock(mNamespaceMutex);
 
-        auto vndkNamespace = android_get_exported_namespace("vndk");
-        if (!vndkNamespace) return;
+    if (mDriverNamespace) {
+        return mDriverNamespace;
+    }
 
-        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 (mDriverPath.empty()) {
+        return nullptr;
+    }
 
-        const std::string llndkLibraries = getSystemNativeLibraries(NativeLibrary::LLNDK);
-        if (llndkLibraries.empty()) {
-            mDriverNamespace = nullptr;
-            return;
-        }
-        if (!android_link_namespaces(mDriverNamespace, nullptr, llndkLibraries.c_str())) {
-            ALOGE("Failed to link default namespace[%s]", dlerror());
-            mDriverNamespace = nullptr;
-            return;
-        }
+    auto vndkNamespace = android_get_exported_namespace("vndk");
+    if (!vndkNamespace) {
+        return nullptr;
+    }
 
-        const std::string vndkspLibraries = getSystemNativeLibraries(NativeLibrary::VNDKSP);
-        if (vndkspLibraries.empty()) {
-            mDriverNamespace = nullptr;
-            return;
-        }
-        if (!android_link_namespaces(mDriverNamespace, vndkNamespace, vndkspLibraries.c_str())) {
-            ALOGE("Failed to link vndk namespace[%s]", dlerror());
-            mDriverNamespace = nullptr;
-            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);
 
-        if (mSphalLibraries.empty()) return;
-
-        // 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;
-        }
-
-        if (!android_link_namespaces(mDriverNamespace, sphalNamespace, mSphalLibraries.c_str())) {
-            ALOGE("Failed to link sphal namespace[%s]", dlerror());
-            mDriverNamespace = nullptr;
-            return;
-        }
-    });
+    if (!linkDriverNamespaceLocked(vndkNamespace)) {
+        mDriverNamespace = nullptr;
+    }
 
     return mDriverNamespace;
 }
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 7d62750..f5d19db 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -129,6 +129,7 @@
     void* loadLibrary(std::string name);
     bool checkAngleRules(void* so);
     void updateUseAngle();
+    bool linkDriverNamespaceLocked(android_namespace_t* vndkNamespace);
 
     GraphicsEnv() = default;
     std::string mDriverPath;
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index d5c46c6..038a432 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -84,6 +84,11 @@
     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 @@
     "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 @@
                         "couldn't find an OpenGL ES implementation, make sure you set %s or %s",
                         HAL_SUBNAME_KEY_PROPERTIES[0], HAL_SUBNAME_KEY_PROPERTIES[1]);
 
-    cnx->libEgl   = load_wrapper(EGL_WRAPPER_DIR "/libEGL.so");
-    cnx->libGles2 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv2.so");
-    cnx->libGles1 = load_wrapper(EGL_WRAPPER_DIR "/libGLESv1_CM.so");
+    if (!cnx->libEgl) {
+        cnx->libEgl = load_wrapper(EGL_WRAPPER_DIR "/libEGL.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 @@
         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);
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 0292d02..6f31ab4 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -58,6 +58,7 @@
     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))
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index 8870d5f..25b1009 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -187,13 +187,9 @@
 
     // 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->dso = loader.open(cnx);
-    }
+    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) {
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 8841a3b..67d69b4 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -217,7 +217,7 @@
     Loader& loader(Loader::getInstance());
 
     egl_connection_t* const cnx = &gEGLImpl;
-    if (cnx->dso && disp.dpy == EGL_NO_DISPLAY) {
+    if (cnx->dso) {
         EGLDisplay dpy = EGL_NO_DISPLAY;
 
         if (cnx->useAngle) {
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 9e112cc..7bb9b59 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -44,7 +44,11 @@
         GLESv2_INDEX = 1
     };
 
-    inline egl_connection_t() : dso(nullptr) {
+    inline egl_connection_t() : dso(nullptr),
+                                libEgl(nullptr),
+                                libGles1(nullptr),
+                                libGles2(nullptr),
+                                systemDriverUnloaded(false) {
 
         char const* const* entries = platform_names;
         EGLFuncPointer* curr = reinterpret_cast<EGLFuncPointer*>(&platform);
@@ -76,6 +80,7 @@
     void*               libGles1;
     void*               libGles2;
 
+    bool                systemDriverUnloaded;
     bool                shouldUseAngle; // Should we attempt to load ANGLE
     bool                angleDecided;   // Have we tried to load ANGLE
     bool                useAngle;       // Was ANGLE successfully loaded