EGL: Load updated EGL/GLES drivers

Because the driver namespace is stored in libgui, and libgui depends
on libEGL, this required a hack for libEGL to access the namespace.
See the comment added in GraphicsEnv.h for details; the summary is
that the libgui->libEGL dependency should go away, and then libEGL can
depend on libgui directly.

For system drivers, the loader would happily load anything named
lib{GLES,EGL,GLESv2,GLESv1_CM}_*.so in /vendor/lib[64]/egl, for
backward-compatibility with the old and no-longer-supported egl.cfg
system. However, it preferred unsuffixed names. That's not actually a
good idea, since the DT_SONAME would clash with the system libraries.
For updated drivers, we only look for suffixes from the
ro.hardware.egl and ro.board.platform system properties, similar to
the Vulkan and HAL library search. A future change (tied to a future
release) will do the same for system drivers.

Bug: 33531483
Change-Id: If6eb7dbbc37f219c999e20a983569d4c4e73bda1
Merged-In: Ibfbb275629b0c6cf9c51314aea1361e81ff72d4b
diff --git a/include/gui/GraphicsEnv.h b/include/gui/GraphicsEnv.h
index 0d3843b..4c7366f 100644
--- a/include/gui/GraphicsEnv.h
+++ b/include/gui/GraphicsEnv.h
@@ -43,4 +43,17 @@
 
 } // namespace android
 
+/* FIXME
+ * Export an un-mangled function that just does
+ *     return android::GraphicsEnv::getInstance().getDriverNamespace();
+ * This allows libEGL to get the function pointer via dlsym, since it can't
+ * directly link against libgui. In a future release, we'll fix this so that
+ * libgui does not depend on graphics API libraries, and libEGL can link
+ * against it. The current dependencies from libgui -> libEGL are:
+ *  - the GLConsumer class, which should be moved to its own library
+ *  - the EGLsyncKHR synchronization in BufferQueue, which is deprecated and
+ *    will be removed soon.
+ */
+extern "C" android_namespace_t* android_getDriverNamespace();
+
 #endif // ANDROID_GUI_GRAPHICS_ENV_H
diff --git a/libs/gui/GraphicsEnv.cpp b/libs/gui/GraphicsEnv.cpp
index ab824d3..68f0f98 100644
--- a/libs/gui/GraphicsEnv.cpp
+++ b/libs/gui/GraphicsEnv.cpp
@@ -75,3 +75,7 @@
 }
 
 } // namespace android
+
+extern "C" android_namespace_t* android_getDriverNamespace() {
+    return android::GraphicsEnv::getInstance().getDriverNamespace();
+}
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 49f501d..5aa2ad0 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -14,6 +14,9 @@
  ** limitations under the License.
  */
 
+//#define LOG_NDEBUG 0
+
+#include <array>
 #include <ctype.h>
 #include <stdlib.h>
 #include <stdio.h>
@@ -23,6 +26,7 @@
 #include <limits.h>
 #include <dirent.h>
 
+#include <android/dlext.h>
 #include <cutils/log.h>
 #include <cutils/properties.h>
 
@@ -154,10 +158,26 @@
 // ----------------------------------------------------------------------------
 
 Loader::Loader()
-    : getProcAddress(NULL) {
+    : getProcAddress(NULL),
+      mLibGui(nullptr),
+      mGetDriverNamespace(nullptr)
+{
+    // FIXME: See note in GraphicsEnv.h about android_getDriverNamespace().
+    // libgui should already be loaded in any process that uses libEGL, but
+    // if for some reason it isn't, then we're not going to get a driver
+    // namespace anyway, so don't force it to be loaded.
+    mLibGui = dlopen("libgui.so", RTLD_NOLOAD | RTLD_LOCAL | RTLD_LAZY);
+    if (!mLibGui) {
+        ALOGD("failed to load libgui: %s", dlerror());
+        return;
+    }
+    mGetDriverNamespace = reinterpret_cast<decltype(mGetDriverNamespace)>(
+            dlsym(mLibGui, "android_getDriverNamespace"));
 }
 
 Loader::~Loader() {
+    if (mLibGui)
+        dlclose(mLibGui);
 }
 
 static void* load_wrapper(const char* path) {
@@ -304,9 +324,7 @@
     }
 }
 
-void *Loader::load_driver(const char* kind,
-        egl_connection_t* cnx, uint32_t mask)
-{
+static void* load_system_driver(const char* kind) {
     class MatchFile {
     public:
         static String8 find(const char* kind) {
@@ -431,11 +449,55 @@
 
     ALOGD("loaded %s", driver_absolute_path);
 
+    return dso;
+}
+
+static const std::array<const char*, 2> HAL_SUBNAME_KEY_PROPERTIES = {{
+    "ro.hardware.egl",
+    "ro.board.platform",
+}};
+
+static void* load_updated_driver(const char* kind, android_namespace_t* ns) {
+    const android_dlextinfo dlextinfo = {
+        .flags = ANDROID_DLEXT_USE_NAMESPACE,
+        .library_namespace = ns,
+    };
+    void* so = nullptr;
+    char prop[PROPERTY_VALUE_MAX + 1];
+    for (auto key : HAL_SUBNAME_KEY_PROPERTIES) {
+        if (property_get(key, prop, nullptr) > 0) {
+            String8 name;
+            name.appendFormat("lib%s_%s.so", kind, prop);
+            so = android_dlopen_ext(name.string(), RTLD_LOCAL | RTLD_NOW,
+                    &dlextinfo);
+            if (so)
+                return so;
+        }
+    }
+    return nullptr;
+}
+
+void *Loader::load_driver(const char* kind,
+        egl_connection_t* cnx, uint32_t mask)
+{
+    void* dso = nullptr;
+    if (mGetDriverNamespace) {
+        android_namespace_t* ns = mGetDriverNamespace();
+        if (ns) {
+            dso = load_updated_driver(kind, ns);
+        }
+    }
+    if (!dso) {
+        dso = load_system_driver(kind);
+        if (!dso)
+            return NULL;
+    }
+
     if (mask & EGL) {
         getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
 
         ALOGE_IF(!getProcAddress,
-                "can't find eglGetProcAddress() in %s", driver_absolute_path);
+                "can't find eglGetProcAddress() in EGL driver library");
 
         egl_t* egl = &cnx->egl;
         __eglMustCastToProperFunctionPointerType* curr =
diff --git a/opengl/libs/EGL/Loader.h b/opengl/libs/EGL/Loader.h
index 8cefe32..04a8e41 100644
--- a/opengl/libs/EGL/Loader.h
+++ b/opengl/libs/EGL/Loader.h
@@ -25,6 +25,8 @@
 #include <utils/Singleton.h>
 #include <utils/String8.h>
 
+#include <gui/GraphicsEnv.h>
+
 #include <EGL/egl.h>
 
 // ----------------------------------------------------------------------------
@@ -53,7 +55,10 @@
     };
     
     getProcAddressType getProcAddress;
-    
+
+    void* mLibGui;
+    decltype(android_getDriverNamespace)* mGetDriverNamespace;
+
 public:
     ~Loader();