gltrace: Add support for tracing running applications.

Currently, to activate OpenGL tracing, an application has to be
start with --opengl-trace option (or have a debug prop set).

This CL adds support for tracing an application which may already
be running. This is implemented as follows:
    - DDMS initiates a JDWP message to the VM indicating that
      opengl traces be enabled.
    - When that message is received, a flag is set that indicates
      that tracing should be enabled.
    - The trace flag is checked during every eglSwap() operation,
      and if it finds that tracing should be active and it isn't,
      then it starts the tracing component.

Change-Id: I3347fe89fc06c7404d7aa9360f4b21e5bf36ebcb
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index d46f83b..bf2477a 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -84,13 +84,20 @@
 static bool sEGLSystraceEnabled;
 static bool sEGLGetErrorEnabled;
 
-int gEGLDebugLevel;
-static int sEGLApplicationDebugLevel;
+static volatile int sEGLDebugLevel;
 
 extern gl_hooks_t gHooksTrace;
 extern gl_hooks_t gHooksSystrace;
 extern gl_hooks_t gHooksErrorTrace;
 
+int getEGLDebugLevel() {
+    return sEGLDebugLevel;
+}
+
+void setEGLDebugLevel(int level) {
+    sEGLDebugLevel = level;
+}
+
 static inline void setGlTraceThreadSpecific(gl_hooks_t const *value) {
     pthread_setspecific(gGLTraceKey, value);
 }
@@ -122,36 +129,36 @@
 }
 
 void initEglDebugLevel() {
-    int propertyLevel = 0;
-    char value[PROPERTY_VALUE_MAX];
+    if (getEGLDebugLevel() == 0) {
+        char value[PROPERTY_VALUE_MAX];
 
-    // check system property only on userdebug or eng builds
-    property_get("ro.debuggable", value, "0");
-    if (value[0] == '0')
-        return;
+        // check system property only on userdebug or eng builds
+        property_get("ro.debuggable", value, "0");
+        if (value[0] == '0')
+            return;
 
-    property_get("debug.egl.debug_proc", value, "");
-    if (strlen(value) > 0) {
-        long pid = getpid();
-        char procPath[128] = {};
-        sprintf(procPath, "/proc/%ld/cmdline", pid);
-        FILE * file = fopen(procPath, "r");
-        if (file) {
-            char cmdline[256] = {};
-            if (fgets(cmdline, sizeof(cmdline) - 1, file)) {
-                if (!strncmp(value, cmdline, strlen(value))) {
-                    // set EGL debug if the "debug.egl.debug_proc" property
-                    // matches the prefix of this application's command line
-                    propertyLevel = 1;
+        property_get("debug.egl.debug_proc", value, "");
+        if (strlen(value) > 0) {
+            FILE * file = fopen("/proc/self/cmdline", "r");
+            if (file) {
+                char cmdline[256];
+                if (fgets(cmdline, sizeof(cmdline), file)) {
+                    if (!strncmp(value, cmdline, strlen(value))) {
+                        // set EGL debug if the "debug.egl.debug_proc" property
+                        // matches the prefix of this application's command line
+                        setEGLDebugLevel(1);
+                    }
                 }
+                fclose(file);
             }
-            fclose(file);
         }
     }
 
-    gEGLDebugLevel = propertyLevel || sEGLApplicationDebugLevel;
-    if (gEGLDebugLevel > 0) {
-        GLTrace_start();
+    if (getEGLDebugLevel() > 0) {
+        if (GLTrace_start() < 0) {
+            ALOGE("Error starting Tracer for OpenGL ES. Disabling..");
+            setEGLDebugLevel(0);
+        }
     }
 }
 
@@ -165,10 +172,11 @@
     } else if (sEGLTraceLevel > 0) {
         setGlTraceThreadSpecific(value);
         setGlThreadSpecific(&gHooksTrace);
-    } else if (gEGLDebugLevel > 0 && value != &gHooksNoContext) {
+    } else if (getEGLDebugLevel() > 0 && value != &gHooksNoContext) {
         setGlTraceThreadSpecific(value);
         setGlThreadSpecific(GLTrace_getGLHooks());
     } else {
+        setGlTraceThreadSpecific(NULL);
         setGlThreadSpecific(value);
     }
 }
@@ -186,9 +194,12 @@
  * Global entry point to allow applications to modify their own debug level.
  * Debugging is enabled if either the application requested it, or if the system property
  * matches the application's name.
+ * Note that this only sets the debug level. The value is read and used either in
+ * initEglDebugLevel() if the application hasn't initialized its display yet, or when
+ * eglSwapBuffers() is called next.
  */
 void EGLAPI setGLDebugLevel(int level) {
-    sEGLApplicationDebugLevel = level;
+    setEGLDebugLevel(level);
 }
 
 #else
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 4e44941..d1f25e0 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -97,7 +97,8 @@
 extern void setGLHooksThreadSpecific(gl_hooks_t const *value);
 extern EGLBoolean egl_init_drivers();
 extern const __eglMustCastToProperFunctionPointerType gExtensionForwarders[MAX_NUMBER_OF_GL_EXTENSIONS];
-extern int gEGLDebugLevel;
+extern int getEGLDebugLevel();
+extern void setEGLDebugLevel(int level);
 extern gl_hooks_t gHooksTrace;
 } // namespace android;
 
@@ -465,7 +466,7 @@
             egl_context_t* c = new egl_context_t(dpy, context, config, cnx,
                     version);
 #if EGL_TRACE
-            if (gEGLDebugLevel > 0)
+            if (getEGLDebugLevel() > 0)
                 GLTrace_eglCreateContext(version, c);
 #endif
             return c;
@@ -578,7 +579,7 @@
             setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
             egl_tls_t::setContext(ctx);
 #if EGL_TRACE
-            if (gEGLDebugLevel > 0)
+            if (getEGLDebugLevel() > 0)
                 GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx);
 #endif
             _c.acquire();
@@ -858,8 +859,31 @@
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
 #if EGL_TRACE
-    if (gEGLDebugLevel > 0)
+    gl_hooks_t const *trace_hooks = getGLTraceThreadSpecific();
+    if (getEGLDebugLevel() > 0) {
+        if (trace_hooks == NULL) {
+            if (GLTrace_start() < 0) {
+                ALOGE("Disabling Tracer for OpenGL ES");
+                setEGLDebugLevel(0);
+            } else {
+                // switch over to the trace version of hooks
+                EGLContext ctx = egl_tls_t::getContext();
+                egl_context_t * const c = get_context(ctx);
+                if (c) {
+                    setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
+                    GLTrace_eglMakeCurrent(c->version, c->cnx->hooks[c->version], ctx);
+                }
+            }
+        }
+
         GLTrace_eglSwapBuffers(dpy, draw);
+    } else if (trace_hooks != NULL) {
+        // tracing is now disabled, so switch back to the non trace version
+        EGLContext ctx = egl_tls_t::getContext();
+        egl_context_t * const c = get_context(ctx);
+        if (c) setGLHooksThreadSpecific(c->cnx->hooks[c->version]);
+        GLTrace_stop();
+    }
 #endif
 
     egl_surface_t const * const s = get_surface(draw);
@@ -1078,7 +1102,7 @@
 
     egl_tls_t::clearTLS();
 #if EGL_TRACE
-    if (gEGLDebugLevel > 0)
+    if (getEGLDebugLevel() > 0)
         GLTrace_eglReleaseThread();
 #endif
     return EGL_TRUE;