summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSiva Velusamy <vsiva@google.com>2012-12-18 14:56:55 -0800
committerSiva Velusamy <vsiva@google.com>2012-12-20 10:38:47 -0800
commita73a97728befb5ba5ad647ab3b60058c4d536ba4 (patch)
tree8636701bc18989ad4d7c9e9948b8c744de2c84d1
parent0859b78db2b094d20efb7b3e725c4732fcdeb4d5 (diff)
downloadframeworks_native-a73a97728befb5ba5ad647ab3b60058c4d536ba4.zip
frameworks_native-a73a97728befb5ba5ad647ab3b60058c4d536ba4.tar.gz
frameworks_native-a73a97728befb5ba5ad647ab3b60058c4d536ba4.tar.bz2
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
-rw-r--r--opengl/libs/EGL/egl.cpp67
-rw-r--r--opengl/libs/EGL/eglApi.cpp34
-rw-r--r--opengl/libs/GLES_trace/DESIGN.txt34
-rw-r--r--opengl/libs/GLES_trace/src/gltrace_eglapi.cpp67
-rw-r--r--opengl/libs/glestrace.h2
5 files changed, 157 insertions, 47 deletions
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 int sEGLApplicationTraceLevel;
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 initEglTraceLevel() {
}
void initEglDebugLevel() {
- int propertyLevel = 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;
+ if (getEGLDebugLevel() == 0) {
+ char value[PROPERTY_VALUE_MAX];
- 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;
+ // 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) {
+ 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 @@ void setGLHooksThreadSpecific(gl_hooks_t const *value) {
} 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 @@ void setGLTraceLevel(int level) {
* 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 @@ namespace android {
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 @@ EGLContext eglCreateContext(EGLDisplay dpy, EGLConfig config,
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 @@ EGLBoolean eglMakeCurrent( EGLDisplay dpy, EGLSurface draw,
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 @@ EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface draw)
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 @@ EGLBoolean eglReleaseThread(void)
egl_tls_t::clearTLS();
#if EGL_TRACE
- if (gEGLDebugLevel > 0)
+ if (getEGLDebugLevel() > 0)
GLTrace_eglReleaseThread();
#endif
return EGL_TRUE;
diff --git a/opengl/libs/GLES_trace/DESIGN.txt b/opengl/libs/GLES_trace/DESIGN.txt
index a189e1d..72a2e15 100644
--- a/opengl/libs/GLES_trace/DESIGN.txt
+++ b/opengl/libs/GLES_trace/DESIGN.txt
@@ -9,9 +9,6 @@ Code Runtime Behavior:
control whether tracing should be enabled for a certain process. If tracing is enabled, this
calls GLTrace_start() to start the trace server.
- Note that initEglTraceLevel() is also called from early_egl_init(), but that happens in the
- context of the zygote, so that invocation has no effect.
-
egl_display_t::initialize() then calls setGLHooksThreadSpecific() where we set the thread
specific gl_hooks structure to point to the trace implementation. From this point on, every
GLES call is redirected to the trace implementation.
@@ -30,6 +27,37 @@ Code Runtime Behavior:
to explore if a more graceful method of stopping the application, or detaching tracing from the
application is required.
+
+Enabling tracing while the application is running:
+
+ In order to allow tracing of an already running application, we allow DdmServer to enable
+ OpenGL tracing. In such a case, the application already has its GL hooks set up to point to the
+ real GL implementation, and we need to switch them to point to the trace implementation.
+
+ This is achieved by checking whether tracing should be enabled at every eglSwap call.
+ (Note: We were already checking for tracing at every eglSwap, the only change now is that
+ the tracing could actually be ON/OFF at runtime - earlier it was set once and never changed).
+
+ If eglSwap detects that tracing should be enabled now, then it performs the following steps:
+ - switch the gl hooks to point to the trace implementation.
+ - call trace eglMakeCurrent to indicate that there is now a new context that is current.
+ - continue on with tracing the eglSwap call.
+ This switches the hooks to point to the trace implementation only for the current context.
+ But the other contexts have their gl hooks updated when they perform eglMakeCurrent.
+
+ The GLTrace version of eglMakeCurrent now has to be updated to allow switching to a context
+ it may not know of. In such a case, it creates a context matching the version that it is now
+ switching to.
+
+Disabling tracing:
+
+ We disable tracing under two conditions:
+ - stop tracing request from DdmServer
+ - gltrace transport gets disconnected from the host.
+ In either case, both actions simply disable the tracing flag. The current context gets its
+ gl hooks restored in the next eglSwap, and the other traced contexts get their gl hooks
+ restored when they perform a eglMakeCurrent.
+
Code Structure:
glestrace.h declares all the hooks exposed by libglestrace. These are used by EGL/egl.cpp and
diff --git a/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp b/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp
index 9698bf9..512d562 100644
--- a/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_eglapi.cpp
@@ -33,6 +33,9 @@ using gltrace::GLTraceState;
using gltrace::GLTraceContext;
using gltrace::TCPStream;
+static pthread_mutex_t sGlTraceStateLock = PTHREAD_MUTEX_INITIALIZER;
+
+static int sGlTraceInProgress;
static GLTraceState *sGLTraceState;
static pthread_t sReceiveThreadId;
@@ -105,33 +108,66 @@ static void *commandReceiveTask(void *arg) {
return NULL;
}
-void GLTrace_start() {
- char udsName[PROPERTY_VALUE_MAX];
+/**
+ * Starts Trace Server and waits for connection from the host.
+ * Returns -1 in case of connection error, 0 otherwise.
+ */
+int GLTrace_start() {
+ int status = 0;
+ int clientSocket = -1;
+ TCPStream *stream = NULL;
+
+ pthread_mutex_lock(&sGlTraceStateLock);
+ if (sGlTraceInProgress) {
+ goto done;
+ }
+
+ char udsName[PROPERTY_VALUE_MAX];
property_get("debug.egl.debug_portname", udsName, "gltrace");
- int clientSocket = gltrace::acceptClientConnection(udsName);
+ clientSocket = gltrace::acceptClientConnection(udsName);
if (clientSocket < 0) {
- ALOGE("Error creating GLTrace server socket. Quitting application.");
- exit(-1);
+ ALOGE("Error creating GLTrace server socket. Tracing disabled.");
+ status = -1;
+ goto done;
}
+ sGlTraceInProgress = 1;
+
// create communication channel to the host
- TCPStream *stream = new TCPStream(clientSocket);
+ stream = new TCPStream(clientSocket);
// initialize tracing state
sGLTraceState = new GLTraceState(stream);
pthread_create(&sReceiveThreadId, NULL, commandReceiveTask, sGLTraceState);
+
+done:
+ pthread_mutex_unlock(&sGlTraceStateLock);
+ return status;
}
void GLTrace_stop() {
- delete sGLTraceState;
- sGLTraceState = NULL;
+ pthread_mutex_lock(&sGlTraceStateLock);
+
+ if (sGlTraceInProgress) {
+ sGlTraceInProgress = 0;
+ delete sGLTraceState;
+ sGLTraceState = NULL;
+ }
+
+ pthread_mutex_unlock(&sGlTraceStateLock);
}
void GLTrace_eglCreateContext(int version, EGLContext c) {
+ pthread_mutex_lock(&sGlTraceStateLock);
+ GLTraceState *state = sGLTraceState;
+ pthread_mutex_unlock(&sGlTraceStateLock);
+
+ if (state == NULL) return;
+
// update trace state for new EGL context
- GLTraceContext *traceContext = sGLTraceState->createTraceContext(version, c);
+ GLTraceContext *traceContext = state->createTraceContext(version, c);
gltrace::setupTraceContextThreadSpecific(traceContext);
// trace command through to the host
@@ -139,8 +175,19 @@ void GLTrace_eglCreateContext(int version, EGLContext c) {
}
void GLTrace_eglMakeCurrent(const unsigned version, gl_hooks_t *hooks, EGLContext c) {
+ pthread_mutex_lock(&sGlTraceStateLock);
+ GLTraceState *state = sGLTraceState;
+ pthread_mutex_unlock(&sGlTraceStateLock);
+
+ if (state == NULL) return;
+
// setup per context state
- GLTraceContext *traceContext = sGLTraceState->getTraceContext(c);
+ GLTraceContext *traceContext = state->getTraceContext(c);
+ if (traceContext == NULL) {
+ GLTrace_eglCreateContext(version, c);
+ traceContext = state->getTraceContext(c);
+ }
+
traceContext->hooks = hooks;
gltrace::setupTraceContextThreadSpecific(traceContext);
diff --git a/opengl/libs/glestrace.h b/opengl/libs/glestrace.h
index a08f97b..868b18d 100644
--- a/opengl/libs/glestrace.h
+++ b/opengl/libs/glestrace.h
@@ -30,7 +30,7 @@ void GLTrace_eglReleaseThread();
void GLTrace_eglSwapBuffers(void*, void*);
/* Start and stop GL Tracing. */
-void GLTrace_start();
+int GLTrace_start();
void GLTrace_stop();
/* Obtain the gl_hooks structure filled with the trace implementation for all GL functions. */