Prevent GPU driver from exposing OpenGL ES 3.0 support

The Adreno GPU driver currently in use breaks various CTS tests when
using its OpenGL ES 3.0 implementation. Falling back to OpenGL ES 2.0
fixes these issues (via ro.opengles.version). This, however, leads to
inconsistent version information between the system property and what
the driver is exposing. Therefore, filter out OpenGL ES 3.x related
information from the OpenGL (ES) interfaces.

Two changes are required:
* The wrappers for glGetString in libGLESv1_CM, libGLESv2 and
  libGLESv3 (same implementation as libGLESv2) are extended to replace
  any 3.x version strings by a 2.0 version string.
* eglGetConfigAttrib must not expose EGL_OPENGL_ES3_BIT_KHR for
  EGL_RENDERABLE_TYPE. It does not have a wrapper yet; this change adds
  a wrapper directly in the EGL library loader.

Issue: FP2N-260
Issue: FP2P-170
Test: run cts --skip-preconditions --skip-device-info -m CtsGraphicsTestCases --test android.opengl.cts.OpenGlEsVersionTest#testOpenGlEsVersion
Depends-On: I1f1b27d06f2c9ddf8b6350031544c37758e5e8c6
Change-Id: I8a0888e95418c147b8d4c455a7892bd53f7d04d8
(cherry picked from commit 380b4fe0cb7447906a4947cee0b709061cddf04f)
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 91a3455..fcc7a3e 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -33,6 +33,8 @@
 #endif
 #include <vndksupport/linker.h>
 
+#include <EGL/eglext.h>
+
 #include "egl_trace.h"
 #include "egldefs.h"
 
@@ -480,6 +482,40 @@
     return nullptr;
 }
 
+namespace
+{
+
+typedef EGLBoolean (*eglGetConfigAttrib_func_t)(
+    EGLDisplay display, EGLConfig config, EGLint attribute, EGLint * value);
+
+eglGetConfigAttrib_func_t eglGetConfigAttrib_func_ptr = nullptr;
+
+/*
+ * Wrapper for eglGetConfigAttrib for masking attributes that indicate
+ * OpenGL ES 3.x support.
+ * The OpenGL ES 3.0 implementation of the driver causes various tests to fail
+ * on Android 7.
+ */
+EGLBoolean eglGetConfigAttrib_wrapper(EGLDisplay display,
+    EGLConfig config,
+    EGLint attribute,
+    EGLint * value)
+{
+    if (!eglGetConfigAttrib_func_ptr) {
+        return EGL_FALSE;
+    }
+
+    const EGLBoolean result = eglGetConfigAttrib_func_ptr(display, config, attribute, value);
+
+    if (attribute == EGL_RENDERABLE_TYPE) {
+        *value = *value & ~EGL_OPENGL_ES3_BIT_KHR;
+    }
+
+    return result;
+}
+
+}
+
 void *Loader::load_driver(const char* kind,
         egl_connection_t* cnx, uint32_t mask)
 {
@@ -510,6 +546,8 @@
         char const * const * api = egl_names;
         while (*api) {
             char const * name = *api;
+            // wrap eglGetConfigAttrib(), see eglGetConfigAttrib_wrapper()
+            const bool loading_eglGetConfigAttrib = (strcmp(name, "eglGetConfigAttrib") == 0);
             __eglMustCastToProperFunctionPointerType f =
                 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
             if (f == NULL) {
@@ -519,6 +557,10 @@
                     f = (__eglMustCastToProperFunctionPointerType)0;
                 }
             }
+            if (f && loading_eglGetConfigAttrib) {
+                eglGetConfigAttrib_func_ptr = (eglGetConfigAttrib_func_t)f;
+                f = (__eglMustCastToProperFunctionPointerType)&eglGetConfigAttrib_wrapper;
+            }
             *curr++ = f;
             api++;
         }
diff --git a/opengl/libs/GLES2/gl2.cpp b/opengl/libs/GLES2/gl2.cpp
index f7fde96..a6823b7 100644
--- a/opengl/libs/GLES2/gl2.cpp
+++ b/opengl/libs/GLES2/gl2.cpp
@@ -306,6 +306,31 @@
         gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
         if(_c) ret = _c->glGetString(name);
     }
+
+    if (name == GL_VERSION) {
+        /*
+         * Replace version strings that indicate OpenGL ES 3.x support.
+         * The OpenGL ES 3.0 implementation of the driver causes various tests
+         * to fail on Android 7.
+         */
+        struct VersionStringReplacement {
+            const char * broken_version_prefix;
+            const size_t check_length;
+            const char * fake_version_string;
+        };
+        const VersionStringReplacement versionStringReplacements[] = {
+            { "OpenGL ES 3.", 12, "OpenGL ES 2.0" },
+            { "OpenGL ES-CM 3.", 15, "OpenGL ES-CM 2.0" },
+            { NULL, 0, NULL }
+        };
+        const VersionStringReplacement * r = versionStringReplacements;
+        for (; r->broken_version_prefix != NULL; ++r) {
+            if (strncmp((const char *)ret, r->broken_version_prefix, r->check_length) == 0) {
+                return (const GLubyte *)r->fake_version_string;
+            }
+        }
+    }
+
     return ret;
 }
 
diff --git a/opengl/libs/GLES_CM/gl.cpp b/opengl/libs/GLES_CM/gl.cpp
index bacd4b4..3015114 100644
--- a/opengl/libs/GLES_CM/gl.cpp
+++ b/opengl/libs/GLES_CM/gl.cpp
@@ -352,5 +352,30 @@
         gl_hooks_t::gl_t const * const _c = &getGlThreadSpecific()->gl;
         ret = _c->glGetString(name);
     }
+
+    if (name == GL_VERSION) {
+        /*
+         * Replace version strings that indicate OpenGL ES 3.x support.
+         * The OpenGL ES 3.0 implementation of the driver causes various tests
+         * to fail on Android 7.
+         */
+        struct VersionStringReplacement {
+            const char * broken_version_prefix;
+            const size_t check_length;
+            const char * fake_version_string;
+        };
+        const VersionStringReplacement versionStringReplacements[] = {
+            { "OpenGL ES 3.", 12, "OpenGL ES 2.0" },
+            { "OpenGL ES-CM 3.", 15, "OpenGL ES-CM 2.0" },
+            { NULL, 0, NULL }
+        };
+        const VersionStringReplacement * r = versionStringReplacements;
+        for (; r->broken_version_prefix != NULL; ++r) {
+            if (strncmp((const char *)ret, r->broken_version_prefix, r->check_length) == 0) {
+                return (const GLubyte *)r->fake_version_string;
+            }
+        }
+    }
+
     return ret;
 }