emulator: opengl: fallback gralloc module

This patch modifies the gralloc.goldfish module to check
that the emulator does, indeed, support GPU emulation.

If this is not the case, it loads the framebuffer-based fallback
module (gralloc.default) explicitely and uses it instead.

This is necessary because sometimes the emulator will be started
in headless mode in restricted environment, i.e. without access
to the display subsystem or GL libraries, which make GPU emulation
impossible.

We check for ro.kernel.qemu.gles which will be either undefined
or set to 0 if the emulator doesn't support GPU emulation, or 1
otherwise.

Change-Id: Ib6b143e6dcdfb44ff2c5b889138d0fb4118bb461
diff --git a/tools/emulator/opengl/system/gralloc/gralloc.cpp b/tools/emulator/opengl/system/gralloc/gralloc.cpp
index 93fe6ac..258b0db 100644
--- a/tools/emulator/opengl/system/gralloc/gralloc.cpp
+++ b/tools/emulator/opengl/system/gralloc/gralloc.cpp
@@ -23,11 +23,12 @@
 #include <cutils/ashmem.h>
 #include <unistd.h>
 #include <errno.h>
+#include <dlfcn.h>
 #include <sys/mman.h>
 #include "HostConnection.h"
 #include "glUtils.h"
 #include <cutils/log.h>
-
+#include <cutils/properties.h>
 
 #define DBG_FUNC DBG("%s\n", __FUNCTION__)
 //
@@ -37,6 +38,16 @@
     gralloc_module_t base;
 };
 
+/* If not NULL, this is a pointer to the fallback module.
+ * This really is gralloc.default, which we'll use if we detect
+ * that the emulator we're running in does not support GPU emulation.
+ */
+static gralloc_module_t*  sFallback;
+static pthread_once_t     sFallbackOnce = PTHREAD_ONCE_INIT;
+
+static void fallback_init(void);  // forward
+
+
 typedef struct _alloc_list_node {
     buffer_handle_t handle;
     _alloc_list_node *next;
@@ -401,6 +412,12 @@
 static int gralloc_register_buffer(gralloc_module_t const* module,
                                    buffer_handle_t handle)
 {
+    pthread_once(&sFallbackOnce, fallback_init);
+    if (sFallback != NULL) {
+        return sFallback->registerBuffer(sFallback, handle);
+    }
+
+
     private_module_t *gr = (private_module_t *)module;
     cb_handle_t *cb = (cb_handle_t *)handle;
     if (!gr || !cb_handle_t::validate(cb)) {
@@ -428,6 +445,10 @@
 static int gralloc_unregister_buffer(gralloc_module_t const* module,
                                      buffer_handle_t handle)
 {
+    if (sFallback != NULL) {
+        return sFallback->unregisterBuffer(sFallback, handle);
+    }
+
     private_module_t *gr = (private_module_t *)module;
     cb_handle_t *cb = (cb_handle_t *)handle;
     if (!gr || !cb_handle_t::validate(cb)) {
@@ -458,6 +479,10 @@
                         int l, int t, int w, int h,
                         void** vaddr)
 {
+    if (sFallback != NULL) {
+        return sFallback->lock(sFallback, handle, usage, l, t, w, h, vaddr);
+    }
+
     private_module_t *gr = (private_module_t *)module;
     cb_handle_t *cb = (cb_handle_t *)handle;
     if (!gr || !cb_handle_t::validate(cb)) {
@@ -546,6 +571,10 @@
 static int gralloc_unlock(gralloc_module_t const* module,
                           buffer_handle_t handle)
 {
+    if (sFallback != NULL) {
+        return sFallback->unlock(sFallback, handle);
+    }
+
     private_module_t *gr = (private_module_t *)module;
     cb_handle_t *cb = (cb_handle_t *)handle;
     if (!gr || !cb_handle_t::validate(cb)) {
@@ -603,6 +632,7 @@
     return 0;
 }
 
+
 static int gralloc_device_open(const hw_module_t* module,
                                const char* name,
                                hw_device_t** device)
@@ -611,6 +641,11 @@
 
     LOGD("gralloc_device_open %s\n", name);
 
+    pthread_once( &sFallbackOnce, fallback_init );
+    if (sFallback != NULL) {
+        return sFallback->common.methods->open(&sFallback->common, name, device);
+    }
+
     if (!strcmp(name, GRALLOC_HARDWARE_GPU0)) {
 
         // Create host connection and keep it in the TLS.
@@ -731,3 +766,32 @@
         reserved_proc : {NULL, }
     }
 };
+
+/* This function is called once to detect whether the emulator supports
+ * GPU emulation (this is done by looking at the qemu.gles kernel
+ * parameter, which must be > 0 if this is the case).
+ *
+ * If not, then load gralloc.default instead as a fallback.
+ */
+static void
+fallback_init(void)
+{
+    char  prop[PROPERTY_VALUE_MAX];
+    void* module;
+
+    property_get("ro.kernel.qemu.gles", prop, "0");
+    if (atoi(prop) > 0) {
+        return;
+    }
+    LOGD("Emulator without GPU emulation detected.");
+    module = dlopen("/system/lib/hw/gralloc.default.so", RTLD_LAZY|RTLD_LOCAL);
+    if (module != NULL) {
+        sFallback = reinterpret_cast<gralloc_module_t*>(dlsym(module, HAL_MODULE_INFO_SYM_AS_STR));
+        if (sFallback == NULL) {
+            dlclose(module);
+        }
+    }
+    if (sFallback == NULL) {
+        LOGE("Could not find software fallback module!?");
+    }
+}