Use opt-in/out logic that lives in the ANGLE APK

The code dlopen's the ANGLE version of libGLESv2.so and then
dlsym/call the ANGLEUseForApplication() function that lives in that
library.  It only calls the opt-in/out logic if the Developer Options
doesn't force the use of ANGLE.  If ANGLE can't be loaded, it also
goes with the application's preference.

Test: Run applications and look at log messages.
Change-Id: I7fa8dec991fbc217157dc12e6466ed4df5fb4020
(cherry picked from commit 85ce86539ac6d56e1c2a37eabed930be82ab4439)
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 90721b8..1421a48 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -38,6 +38,18 @@
 
 extern "C" {
   android_namespace_t* android_get_exported_namespace(const char*);
+
+  // TODO(ianelliott@): Get this from an ANGLE header:
+  typedef enum ANGLEPreference {
+      ANGLE_NO_PREFERENCE = 0,
+      ANGLE_PREFER_NATIVE = 1,
+      ANGLE_PREFER_ANGLE = 2,
+  } ANGLEPreference;
+
+  // TODO(ianelliott@): Get this from an ANGLE header:
+  typedef bool (*fpANGLEUseForApplication)(const char* appName, const char* deviceMfr,
+                                           const char* deviceModel, ANGLEPreference developerOption,
+                                           ANGLEPreference appPreference);
 }
 
 // ----------------------------------------------------------------------------
@@ -475,6 +487,18 @@
     return nullptr;
 }
 
+static ANGLEPreference getAnglePref(const char* app_pref) {
+    if (app_pref == nullptr)
+        return ANGLE_NO_PREFERENCE;
+
+    if (strcmp(app_pref, "angle") == 0) {
+        return ANGLE_PREFER_ANGLE;
+    } else if (strcmp(app_pref, "native") == 0) {
+        return ANGLE_PREFER_NATIVE;
+    }
+    return ANGLE_NO_PREFERENCE;
+}
+
 static void* load_angle(const char* kind, egl_connection_t* cnx) {
     // Only attempt to load ANGLE libs
     if (strcmp(kind, "EGL") != 0 && strcmp(kind, "GLESv2") != 0 && strcmp(kind, "GLESv1_CM") != 0)
@@ -489,23 +513,54 @@
     const char* app_pref = android_getAngleAppPref();
     bool developer_opt_in = android_getAngleDeveloperOptIn();
 
-    if (ns) {
-        // If we got a namespce for ANGLE, check any other conditions
-        // before loading from it.
-        // TODO: Call opt-in logic rather than use pref directly
-        //       app_pref will be "angle", "native", or "dontcare"
-        if ((developer_opt_in || !strcmp(app_pref, "angle"))) {
-            so = load_angle_from_namespace(kind, ns);
+    // Determine whether or not to use ANGLE:
+    ANGLEPreference developer_option = developer_opt_in ? ANGLE_PREFER_ANGLE : ANGLE_NO_PREFERENCE;
+    bool use_angle = (developer_option == ANGLE_PREFER_ANGLE);
+
+    if (use_angle) {
+        ALOGV("User set \"Developer Options\" to force the use of ANGLE");
+    } else {
+        // The "Developer Options" value wasn't set to force the use of ANGLE.  Need to temporarily
+        // load ANGLE and call the updatable opt-in/out logic:
+        std::string app_name_str = app_name ? app_name : "";
+        char manufacturer[PROPERTY_VALUE_MAX];
+        char model[PROPERTY_VALUE_MAX];
+        property_get("ro.product.manufacturer", manufacturer, "UNSET");
+        property_get("ro.product.model", model, "UNSET");
+        ANGLEPreference app_preference = getAnglePref(android_getAngleAppPref());
+
+        so = load_angle_from_namespace("GLESv2", ns);
+        if (so) {
+            ALOGV("Temporarily loaded ANGLE's opt-in/out logic from namespace");
+            fpANGLEUseForApplication fp =
+                    (fpANGLEUseForApplication)dlsym(so, "ANGLEUseForApplication");
+            if (fp) {
+                use_angle = (fp)(app_name_str.c_str(), manufacturer, model, developer_option,
+                                 app_preference);
+                ALOGV("Result of opt-in/out logic is %s", use_angle ? "true" : "false");
+            }
+
+            ALOGV("Close temporarily-loaded ANGLE opt-in/out logic");
+            dlclose(so);
+            so = nullptr;
+        } else {
+            // We weren't able to load and call the updateable opt-in/out logic.
+            // If we can't load the library, there is no ANGLE available.
+            use_angle = false;
+            ALOGV("Could not temporarily-load the ANGLE opt-in/out logic, cannot use ANGLE.");
         }
     }
+    if (use_angle) {
+        so = load_angle_from_namespace(kind, ns);
+    }
 
     if (so) {
-        ALOGD("Loaded ANGLE %s library for %s (instead of native)",
+        ALOGV("Loaded ANGLE %s library for %s (instead of native)",
               kind, app_name ? app_name : "nullptr");
         property_get("debug.angle.backend", prop, "UNSET");
-        ALOGD("ANGLE's backend set to %s", prop);
+        ALOGV("ANGLE's backend set to %s", prop);
         property_get("debug.hwui.renderer", prop, "UNSET");
-        ALOGD("Skia's renderer set to %s", prop);
+        ALOGV("Skia's renderer set to %s", prop);
         cnx->useAngle = true;
         // Find and load vendor libEGL for ANGLE
         if (!cnx->vendorEGL) {
@@ -513,7 +568,7 @@
         }
         return so;
     } else {
-        ALOGD("Loaded native %s library for %s (instead of ANGLE)",
+        ALOGV("Loaded native %s library for %s (instead of ANGLE)",
               kind, app_name ? app_name : "nullptr");
     }