Merge change 26109 into eclair

* changes:
  KeyStore: add java interface.
diff --git a/libs/audioflinger/AudioFlinger.cpp b/libs/audioflinger/AudioFlinger.cpp
index add358b..e534447 100644
--- a/libs/audioflinger/AudioFlinger.cpp
+++ b/libs/audioflinger/AudioFlinger.cpp
@@ -307,6 +307,9 @@
     if (lStatus == NO_ERROR) {
         trackHandle = new TrackHandle(track);
     } else {
+        // remove local strong reference to Client before deleting the Track so that the Client
+        // destructor is called by the TrackBase destructor with mLock held
+        client.clear();
         track.clear();
     }
 
@@ -707,10 +710,10 @@
     }
 }
 
-void AudioFlinger::removeClient(pid_t pid)
+// removeClient_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::removeClient_l(pid_t pid)
 {
-    LOGV("removeClient() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
-    Mutex::Autolock _l(mLock);
+    LOGV("removeClient_l() pid %d, tid %d, calling tid %d", pid, gettid(), IPCThreadState::self()->getCallingPid());
     mClients.removeItem(pid);
 }
 
@@ -2078,7 +2081,10 @@
         }
     }
     mCblkMemory.clear();            // and free the shared memory
-    mClient.clear();
+    if (mClient != NULL) {
+        Mutex::Autolock _l(mClient->audioFlinger()->mLock);
+        mClient.clear();
+    }
 }
 
 void AudioFlinger::ThreadBase::TrackBase::releaseBuffer(AudioBufferProvider::Buffer* buffer)
@@ -2712,9 +2718,10 @@
     // 1 MB of address space is good for 32 tracks, 8 buffers each, 4 KB/buffer
 }
 
+// Client destructor must be called with AudioFlinger::mLock held
 AudioFlinger::Client::~Client()
 {
-    mAudioFlinger->removeClient(mPid);
+    mAudioFlinger->removeClient_l(mPid);
 }
 
 const sp<MemoryDealer>& AudioFlinger::Client::heap() const
@@ -2820,6 +2827,9 @@
                                                    format, channelCount, frameCount, flags);
     }
     if (recordTrack->getCblk() == NULL) {
+        // remove local strong reference to Client before deleting the RecordTrack so that the Client
+        // destructor is called by the TrackBase destructor with mLock held
+        client.clear();
         recordTrack.clear();
         lStatus = NO_MEMORY;
         goto Exit;
diff --git a/libs/audioflinger/AudioFlinger.h b/libs/audioflinger/AudioFlinger.h
index 7a6641f..3699019 100644
--- a/libs/audioflinger/AudioFlinger.h
+++ b/libs/audioflinger/AudioFlinger.h
@@ -189,6 +189,8 @@
         virtual             ~Client();
         const sp<MemoryDealer>&     heap() const;
         pid_t               pid() const { return mPid; }
+        sp<AudioFlinger>    audioFlinger() { return mAudioFlinger; }
+
     private:
                             Client(const Client&);
                             Client& operator = (const Client&);
@@ -641,7 +643,7 @@
     friend class PlaybackThread::Track;
 
 
-                void        removeClient(pid_t pid);
+                void        removeClient_l(pid_t pid);
 
 
     // record thread
diff --git a/libs/surfaceflinger/Layer.cpp b/libs/surfaceflinger/Layer.cpp
index 8dfc2cf..5ff9284 100644
--- a/libs/surfaceflinger/Layer.cpp
+++ b/libs/surfaceflinger/Layer.cpp
@@ -88,7 +88,6 @@
         mBuffers[i].clear();
         mWidth = mHeight = 0;
     }
-    mSurface.clear();
 }
 
 sp<LayerBaseClient::Surface> Layer::createSurface() const
@@ -99,7 +98,8 @@
 status_t Layer::ditch()
 {
     // the layer is not on screen anymore. free as much resources as possible
-    destroy();
+    //destroy();
+    mSurface.clear();
     return NO_ERROR;
 }
 
diff --git a/libs/surfaceflinger/SurfaceFlinger.cpp b/libs/surfaceflinger/SurfaceFlinger.cpp
index e87b563..831c446 100644
--- a/libs/surfaceflinger/SurfaceFlinger.cpp
+++ b/libs/surfaceflinger/SurfaceFlinger.cpp
@@ -1084,9 +1084,12 @@
 
 status_t SurfaceFlinger::purgatorizeLayer_l(const sp<LayerBase>& layerBase)
 {
-    // remove the layer from the main list (through a transaction).
+    // First add the layer to the purgatory list, which makes sure it won't 
+    // go away, then remove it from the main list (through a transaction).
     ssize_t err = removeLayer_l(layerBase);
-
+    if (err >= 0) {
+        mLayerPurgatory.add(layerBase);
+    }
     // it's possible that we don't find a layer, because it might
     // have been destroyed already -- this is not technically an error
     // from the user because there is a race between BClient::destroySurface(),
@@ -1359,8 +1362,18 @@
              * to use the purgatory.
              */
             status_t err = flinger->removeLayer_l(l);
-            LOGE_IF(err<0 && err != NAME_NOT_FOUND,
-                    "error removing layer=%p (%s)", l.get(), strerror(-err));
+            if (err == NAME_NOT_FOUND) {
+                // The surface wasn't in the current list, which means it was
+                // removed already, which means it is in the purgatory, 
+                // and need to be removed from there.
+                // This needs to happen from the main thread since its dtor
+                // must run from there (b/c of OpenGL ES). Additionally, we
+                // can't really acquire our internal lock from 
+                // destroySurface() -- see postMessage() below.
+                ssize_t idx = flinger->mLayerPurgatory.remove(l);
+                LOGE_IF(idx < 0,
+                        "layer=%p is not in the purgatory list", l.get());
+            }
             return true;
         }
     };
diff --git a/libs/surfaceflinger/SurfaceFlinger.h b/libs/surfaceflinger/SurfaceFlinger.h
index f207f85..a34889a 100644
--- a/libs/surfaceflinger/SurfaceFlinger.h
+++ b/libs/surfaceflinger/SurfaceFlinger.h
@@ -312,6 +312,7 @@
     volatile    int32_t                 mTransactionCount;
                 Condition               mTransactionCV;
                 bool                    mResizeTransationPending;
+                SortedVector< sp<LayerBase> > mLayerPurgatory;
                 
                 // protected by mStateLock (but we could use another lock)
                 Tokenizer                               mTokens;
diff --git a/libs/utils/ResourceTypes.cpp b/libs/utils/ResourceTypes.cpp
index f80843d..a5a8cc9 100644
--- a/libs/utils/ResourceTypes.cpp
+++ b/libs/utils/ResourceTypes.cpp
@@ -1740,7 +1740,11 @@
     const int e = Res_GETENTRY(resID);
 
     if (p < 0) {
-        LOGW("No package identifier when getting name for resource number 0x%08x", resID);
+        if (Res_GETPACKAGE(resID)+1 == 0) {
+            LOGW("No package identifier when getting name for resource number 0x%08x", resID);
+        } else {
+            LOGW("Resources don't contain pacakge for resource number 0x%08x", resID);
+        }
         return false;
     }
     if (t < 0) {
@@ -1786,7 +1790,11 @@
     const int e = Res_GETENTRY(resID);
 
     if (p < 0) {
-        LOGW("No package identifier when getting value for resource number 0x%08x", resID);
+        if (Res_GETPACKAGE(resID)+1 == 0) {
+            LOGW("No package identifier when getting name for resource number 0x%08x", resID);
+        } else {
+            LOGW("Resources don't contain pacakge for resource number 0x%08x", resID);
+        }
         return BAD_INDEX;
     }
     if (t < 0) {
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index d51b333..7e7da1b 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -222,19 +222,28 @@
     }
 }
 
-void *Loader::load_driver(const char* driver, gl_hooks_t* hooks, uint32_t mask)
+void *Loader::load_driver(const char* driver_absolute_path,
+        gl_hooks_t* hooks, uint32_t mask)
 {
-    void* dso = dlopen(driver, RTLD_NOW | RTLD_LOCAL);
-    if (dso == 0)
+    if (access(driver_absolute_path, R_OK)) {
+        // this happens often, we don't want to log an error
         return 0;
+    }
 
-    LOGD("loaded %s", driver);
+    void* dso = dlopen(driver_absolute_path, RTLD_NOW | RTLD_LOCAL);
+    if (dso == 0) {
+        const char* err = dlerror();
+        LOGE("load_driver(%s): %s", driver_absolute_path, err?err:"unknown");
+        return 0;
+    }
+
+    LOGD("loaded %s", driver_absolute_path);
 
     if (mask & EGL) {
         getProcAddress = (getProcAddressType)dlsym(dso, "eglGetProcAddress");
 
         LOGE_IF(!getProcAddress, 
-                "can't find eglGetProcAddress() in %s", driver);        
+                "can't find eglGetProcAddress() in %s", driver_absolute_path);
 
         gl_hooks_t::egl_t* egl = &hooks->egl;
         __eglMustCastToProperFunctionPointerType* curr =
diff --git a/opengl/tests/gl2_basic/gl2_basic.cpp b/opengl/tests/gl2_basic/gl2_basic.cpp
index d4887ba..f97d347 100644
--- a/opengl/tests/gl2_basic/gl2_basic.cpp
+++ b/opengl/tests/gl2_basic/gl2_basic.cpp
@@ -21,8 +21,8 @@
 #include <sys/resource.h>
 
 #include <EGL/egl.h>
-#include <GLES/gl.h>
-#include <GLES/glext.h>
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
 
 #include <utils/Timers.h>
 
@@ -31,144 +31,267 @@
 
 using namespace android;
 
-static void printGLString(const char *name, GLenum s)
-{
-     fprintf(stderr, "printGLString %s, %d\n", name, s);
-#if 0 // causes hangs
-     const char *v = (const char *)glGetString(s);
-     int error = glGetError();
-     fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error,
-         (unsigned int)v);
-     if ((v < (const char*) 0) || (v > (const char*) 0x10000))
-         fprintf(stderr, "GL %s = %s\n", name, v);
-     else
-         fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v);
-#endif
+static void printGLString(const char *name, GLenum s) {
+    // fprintf(stderr, "printGLString %s, %d\n", name, s);
+    const char *v = (const char *) glGetString(s);
+    // int error = glGetError();
+    // fprintf(stderr, "glGetError() = %d, result of glGetString = %x\n", error,
+    //        (unsigned int) v);
+    // if ((v < (const char*) 0) || (v > (const char*) 0x10000))
+    //    fprintf(stderr, "GL %s = %s\n", name, v);
+    // else
+    //    fprintf(stderr, "GL %s = (null) 0x%08x\n", name, (unsigned int) v);
+    fprintf(stderr, "GL %s = %s\n", name, v);
 }
 
 static const char* eglErrorToString[] = {
-    "EGL_SUCCESS",      // 0x3000 12288
-    "EGL_NOT_INITIALIZED",
-    "EGL_BAD_ACCESS",   // 0x3002 12290
-    "EGL_BAD_ALLOC",
-    "EGL_BAD_ATTRIBUTE",
-    "EGL_BAD_CONFIG",
-    "EGL_BAD_CONTEXT",  // 0x3006 12294
-    "EGL_BAD_CURRENT_SURFACE",
-    "EGL_BAD_DISPLAY",
-    "EGL_BAD_MATCH",
-    "EGL_BAD_NATIVE_PIXMAP",
-    "EGL_BAD_NATIVE_WINDOW",
-    "EGL_BAD_PARAMETER",  // 0x300c 12300
-    "EGL_BAD_SURFACE"
-};
+        "EGL_SUCCESS", // 0x3000 12288
+        "EGL_NOT_INITIALIZED",
+        "EGL_BAD_ACCESS", // 0x3002 12290
+        "EGL_BAD_ALLOC", "EGL_BAD_ATTRIBUTE",
+        "EGL_BAD_CONFIG",
+        "EGL_BAD_CONTEXT", // 0x3006 12294
+        "EGL_BAD_CURRENT_SURFACE", "EGL_BAD_DISPLAY", "EGL_BAD_MATCH",
+        "EGL_BAD_NATIVE_PIXMAP", "EGL_BAD_NATIVE_WINDOW", "EGL_BAD_PARAMETER", // 0x300c 12300
+        "EGL_BAD_SURFACE" };
 
 static void checkEglError(const char* op, EGLBoolean returnVal = EGL_TRUE) {
     if (returnVal != EGL_TRUE) {
         fprintf(stderr, "%s() returned %d\n", op, returnVal);
     }
 
-    for(EGLint error = eglGetError();
-		error != EGL_SUCCESS;
-	error = eglGetError()) {
+    for (EGLint error = eglGetError(); error != EGL_SUCCESS; error
+            = eglGetError()) {
         const char* errorString = "unknown";
         if (error >= EGL_SUCCESS && error <= EGL_BAD_SURFACE) {
             errorString = eglErrorToString[error - EGL_SUCCESS];
         }
-        fprintf(stderr, "after %s() eglError %s (0x%x)\n", op,
-            errorString, error);
+        fprintf(stderr, "after %s() eglError %s (0x%x)\n", op, errorString,
+                error);
     }
 }
 
-int main(int argc, char** argv)
-{
+static void checkGlError(const char* op) {
+    for (GLint error = glGetError(); error; error
+            = glGetError()) {
+        fprintf(stderr, "after %s() glError (0x%x)\n", op, error);
+    }
+}
+
+static const char gVertexShader[] = "attribute vec4 vPosition;\n"
+    "void main() {\n"
+    "  gl_Position = vPosition;\n"
+    "}\n";
+
+static const char gFragmentShader[] = "precision mediump float;\n"
+    "void main() {\n"
+    "  gl_FragColor = vec4(0.0, 1.0, 0.0, 1.0);\n"
+    "}\n";
+
+GLuint loadShader(GLenum shaderType, const char* pSource) {
+    GLuint shader = glCreateShader(shaderType);
+    if (shader) {
+        glShaderSource(shader, 1, &pSource, NULL);
+        glCompileShader(shader);
+        GLint compiled = 0;
+        glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
+        if (!compiled) {
+            GLint infoLen = 0;
+            glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
+            if (infoLen) {
+                char* buf = (char*) malloc(infoLen);
+                if (buf) {
+                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
+                    fprintf(stderr, "Could not compile shader %d:\n%s\n",
+                            shaderType, buf);
+                    free(buf);
+                }
+                glDeleteShader(shader);
+                shader = 0;
+            }
+        }
+    }
+    return shader;
+}
+
+GLuint createProgram(const char* pVertexSource, const char* pFragmentSource) {
+    GLuint vertexShader = loadShader(GL_VERTEX_SHADER, pVertexSource);
+    if (!vertexShader) {
+        return 0;
+    }
+
+    GLuint pixelShader = loadShader(GL_FRAGMENT_SHADER, pFragmentSource);
+    if (!pixelShader) {
+        return 0;
+    }
+
+    GLuint program = glCreateProgram();
+    if (program) {
+        glAttachShader(program, vertexShader);
+        checkGlError("glAttachShader");
+        glAttachShader(program, pixelShader);
+        checkGlError("glAttachShader");
+        glLinkProgram(program);
+        GLint linkStatus = GL_FALSE;
+        glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
+        if (linkStatus != GL_TRUE) {
+            GLint bufLength = 0;
+            glGetProgramiv(program, GL_INFO_LOG_LENGTH, &bufLength);
+            if (bufLength) {
+                char* buf = (char*) malloc(bufLength);
+                if (buf) {
+                    glGetProgramInfoLog(program, bufLength, NULL, buf);
+                    fprintf(stderr, "Could not link program:\n%s\n", buf);
+                    free(buf);
+                }
+            }
+            glDeleteProgram(program);
+            program = 0;
+        }
+    }
+    return program;
+}
+
+GLuint gProgram;
+GLuint gvPositionHandle;
+
+bool setupGraphics(int w, int h) {
+    gProgram = createProgram(gVertexShader, gFragmentShader);
+    if (!gProgram) {
+        return false;
+    }
+    gvPositionHandle = glGetAttribLocation(gProgram, "vPosition");
+    checkGlError("glGetAttribLocation");
+    fprintf(stderr, "glGetAttribLocation(\"vPosition\") = %d\n",
+            gvPositionHandle);
+
+    glViewport(0, 0, w, h);
+    checkGlError("glViewport");
+    return true;
+}
+
+const GLfloat gTriangleVertices[] = { 0.0f, 0.5f, -0.5f, -0.5f,
+        0.5f, -0.5f };
+
+void renderFrame() {
+    glClearColor(0.0f, 0.0f, 1.0f, 1.0f);
+    checkGlError("glClearColor");
+    glClear( GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
+    checkGlError("glClear");
+
+    glUseProgram(gProgram);
+    checkGlError("glUseProgram");
+
+    glVertexAttribPointer(gvPositionHandle, 2, GL_FLOAT, GL_FALSE, 0, gTriangleVertices);
+    checkGlError("glVertexAttribPointer");
+    glEnableVertexAttribArray(gvPositionHandle);
+    checkGlError("glEnableVertexAttribArray");
+    glDrawArrays(GL_TRIANGLES, 0, 3);
+    checkGlError("glDrawArrays");
+}
+
+int main(int argc, char** argv) {
     EGLBoolean returnValue;
     EGLConfig configs[2];
     EGLint config_count;
 
-	EGLint context_attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
-    EGLint s_configAttribs[] = {
-	EGL_BUFFER_SIZE,     EGL_DONT_CARE,
-	EGL_RED_SIZE,        5,
-	EGL_GREEN_SIZE,      6,
-	EGL_BLUE_SIZE,       5,
-	EGL_DEPTH_SIZE,      8,
-	EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-	EGL_NONE
-     };
+    EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
+    EGLint s_configAttribs[] = { EGL_BUFFER_SIZE, EGL_DONT_CARE, EGL_RED_SIZE,
+            5, EGL_GREEN_SIZE, 6, EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 8,
+            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL_NONE };
 
-     EGLint majorVersion;
-     EGLint minorVersion;
-     EGLContext context;
-     EGLSurface surface;
-     EGLint w, h;
+    EGLint s_configAttribs2[] =
+    {
+            EGL_DEPTH_SIZE,     16,
+            EGL_NONE
+    };
 
-     EGLDisplay dpy;
+    EGLint majorVersion;
+    EGLint minorVersion;
+    EGLContext context;
+    EGLSurface surface;
+    EGLint w, h;
 
-     EGLNativeWindowType window = 0;
-     window = android_createDisplaySurface();
+    EGLDisplay dpy;
 
-     checkEglError("<init>");
-     dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-     checkEglError("eglGetDisplay");
-     if (dpy == EGL_NO_DISPLAY) {
-         printf("eglGetDisplay returned EGL_NO_DISPLAY.\n");
-         return 0;
-     }
-     returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
-     checkEglError("eglInitialize", returnValue);
-     fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion);
+    EGLNativeWindowType window = 0;
+    window = android_createDisplaySurface();
 
-     returnValue = eglGetConfigs (dpy, configs, 2, &config_count);
-     checkEglError("eglGetConfigs", returnValue);
-     fprintf(stderr, "Config count: %d\n", config_count);
-     for(int i = 0; i < config_count; i++) {
+    checkEglError("<init>");
+    dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    checkEglError("eglGetDisplay");
+    if (dpy == EGL_NO_DISPLAY) {
+        printf("eglGetDisplay returned EGL_NO_DISPLAY.\n");
+        return 0;
+    }
+
+    returnValue = eglInitialize(dpy, &majorVersion, &minorVersion);
+    checkEglError("eglInitialize", returnValue);
+    fprintf(stderr, "EGL version %d.%d\n", majorVersion, minorVersion);
+    if (returnValue != EGL_TRUE) {
+        printf("eglInitialize failed\n");
+        return 0;
+    }
+
+    returnValue = eglGetConfigs(dpy, configs, 2, &config_count);
+    checkEglError("eglGetConfigs", returnValue);
+    fprintf(stderr, "Config count: %d\n", config_count);
+    for (int i = 0; i < config_count; i++) {
         fprintf(stderr, "%d: 0x%08x\n", i, (unsigned int) configs[i]);
-     }
+    }
+
 #if 0
-     EGLConfig config;
-     EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &config);
-     checkEglError("EGLUtils::selectConfigForNativeWindow");
+    EGLConfig config;
+    EGLUtils::selectConfigForNativeWindow(dpy, s_configAttribs, window, &config);
+    checkEglError("EGLUtils::selectConfigForNativeWindow");
 #else
-    int chooseConfigResult = eglChooseConfig(dpy, s_configAttribs, configs, 2, &config_count);
+    int chooseConfigResult = eglChooseConfig(dpy, s_configAttribs2, configs, 2,
+            &config_count);
     checkEglError("eglChooseConfig", chooseConfigResult);
-    if (chooseConfigResult != EGL_TRUE )

-    {

+    if (chooseConfigResult != EGL_TRUE) {
         printf("eglChooseConfig failed\n");
-        return 0;

+        return 0;
     }
 #endif
 
-     surface = eglCreateWindowSurface(dpy, configs[0], window, NULL);
-     checkEglError("eglCreateWindowSurface");
-     if (surface == EGL_NO_SURFACE)
-	 {
-         printf("gelCreateWindowSurface failed.\n");
-         return 0;
-	 }
-     EGLint gl2_0Attribs[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
+    surface = eglCreateWindowSurface(dpy, configs[0], window, NULL);
+    checkEglError("eglCreateWindowSurface");
+    if (surface == EGL_NO_SURFACE) {
+        printf("gelCreateWindowSurface failed.\n");
+        return 0;
+    }
+    EGLint gl2_0Attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
 
-     context = eglCreateContext(dpy, configs[0], EGL_NO_CONTEXT, context_attribs);
-     checkEglError("eglCreateContext");
-	 if (context == EGL_NO_CONTEXT)
-     {
+    context = eglCreateContext(dpy, configs[0], EGL_NO_CONTEXT, context_attribs);
+    checkEglError("eglCreateContext");
+    if (context == EGL_NO_CONTEXT) {
         printf("eglCreateContext failed\n");
         return 0;
-	 }
-     eglMakeCurrent(dpy, surface, surface, context);
-     checkEglError("eglMakeCurrent");
-     eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
-     checkEglError("eglQuerySurface");
-     eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
-     checkEglError("eglQuerySurface");
-     GLint dim = w<h ? w : h;
+    }
+    eglMakeCurrent(dpy, surface, surface, context);
+    checkEglError("eglMakeCurrent");
+    eglQuerySurface(dpy, surface, EGL_WIDTH, &w);
+    checkEglError("eglQuerySurface");
+    eglQuerySurface(dpy, surface, EGL_HEIGHT, &h);
+    checkEglError("eglQuerySurface");
+    GLint dim = w < h ? w : h;
 
-     fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
+    fprintf(stderr, "Window dimensions: %d x %d\n", w, h);
 
-     printGLString("Version", GL_VERSION);
-     printGLString("Vendor", GL_VENDOR);
-     printGLString("Renderer", GL_RENDERER);
-     printGLString("Extensions", GL_EXTENSIONS);
+    printGLString("Version", GL_VERSION);
+    printGLString("Vendor", GL_VENDOR);
+    printGLString("Renderer", GL_RENDERER);
+    printGLString("Extensions", GL_EXTENSIONS);
 
-     return 0;
+    if(!setupGraphics(w, h)) {
+        fprintf(stderr, "Could not set up graphics.\n");
+        return 0;
+    }
+
+    for (;;) {
+        renderFrame();
+        eglSwapBuffers(dpy, surface);
+    }
+
+    return 0;
 }