Merge "Add API's for normalizing MIME's and URI's."
diff --git a/include/ui/GraphicLog.h b/include/ui/GraphicLog.h
deleted file mode 100644
index ee1b09a..0000000
--- a/include/ui/GraphicLog.h
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef _UI_GRAPHIC_LOG_H
-#define _UI_GRAPHIC_LOG_H
-
-#include <utils/Singleton.h>
-#include <cutils/compiler.h>
-
-namespace android {
-
-class GraphicLog : public Singleton<GraphicLog>
-{
-    int32_t mEnabled;
-    static void logImpl(int32_t tag, int32_t buffer);
-    static void logImpl(int32_t tag, int32_t identity, int32_t buffer);
-
-public:
-    enum {
-        SF_APP_DEQUEUE_BEFORE   = 60100,
-        SF_APP_DEQUEUE_AFTER    = 60101,
-        SF_APP_LOCK_BEFORE      = 60102,
-        SF_APP_LOCK_AFTER       = 60103,
-        SF_APP_QUEUE            = 60104,
-
-        SF_REPAINT              = 60105,
-        SF_COMPOSITION_COMPLETE = 60106,
-        SF_UNLOCK_CLIENTS       = 60107,
-        SF_SWAP_BUFFERS         = 60108,
-        SF_REPAINT_DONE         = 60109,
-
-        SF_FB_POST_BEFORE       = 60110,
-        SF_FB_POST_AFTER        = 60111,
-        SF_FB_DEQUEUE_BEFORE    = 60112,
-        SF_FB_DEQUEUE_AFTER     = 60113,
-        SF_FB_LOCK_BEFORE       = 60114,
-        SF_FB_LOCK_AFTER        = 60115,
-    };
-
-    inline void log(int32_t tag, int32_t buffer) {
-        if (CC_UNLIKELY(mEnabled))
-            logImpl(tag, buffer);
-    }
-    inline void log(int32_t tag, int32_t identity, int32_t buffer) {
-        if (CC_UNLIKELY(mEnabled))
-            logImpl(tag, identity, buffer);
-    }
-
-    GraphicLog();
-
-    void setEnabled(bool enable);
-};
-
-}
-
-#endif // _UI_GRAPHIC_LOG_H
-
diff --git a/include/utils/TypeHelpers.h b/include/utils/TypeHelpers.h
index 7b4fb70..1f2c2d5 100644
--- a/include/utils/TypeHelpers.h
+++ b/include/utils/TypeHelpers.h
@@ -233,19 +233,15 @@
     }
 };
 
-template<>
 template <typename K, typename V>
 struct trait_trivial_ctor< key_value_pair_t<K, V> >
 { enum { value = aggregate_traits<K,V>::has_trivial_ctor }; };
-template<> 
 template <typename K, typename V>
 struct trait_trivial_dtor< key_value_pair_t<K, V> >
 { enum { value = aggregate_traits<K,V>::has_trivial_dtor }; };
-template<> 
 template <typename K, typename V>
 struct trait_trivial_copy< key_value_pair_t<K, V> >
 { enum { value = aggregate_traits<K,V>::has_trivial_copy }; };
-template<> 
 template <typename K, typename V>
 struct trait_trivial_move< key_value_pair_t<K, V> >
 { enum { value = aggregate_traits<K,V>::has_trivial_move }; };
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index a42c336..629b899 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -692,7 +692,7 @@
         
         case BR_ACQUIRE_RESULT:
             {
-                LOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
+                ALOG_ASSERT(acquireResult != NULL, "Unexpected brACQUIRE_RESULT");
                 const int32_t result = mIn.readInt32();
                 if (!acquireResult) continue;
                 *acquireResult = result ? NO_ERROR : INVALID_OPERATION;
@@ -703,7 +703,7 @@
             {
                 binder_transaction_data tr;
                 err = mIn.read(&tr, sizeof(tr));
-                LOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
+                ALOG_ASSERT(err == NO_ERROR, "Not enough command data for brREPLY");
                 if (err != NO_ERROR) goto finish;
 
                 if (reply) {
@@ -752,7 +752,7 @@
 
 status_t IPCThreadState::talkWithDriver(bool doReceive)
 {
-    LOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");
+    ALOG_ASSERT(mProcess->mDriverFD >= 0, "Binder driver is not opened");
     
     binder_write_read bwr;
     
@@ -905,7 +905,7 @@
     case BR_ACQUIRE:
         refs = (RefBase::weakref_type*)mIn.readInt32();
         obj = (BBinder*)mIn.readInt32();
-        LOG_ASSERT(refs->refBase() == obj,
+        ALOG_ASSERT(refs->refBase() == obj,
                    "BR_ACQUIRE: object %p does not match cookie %p (expected %p)",
                    refs, obj, refs->refBase());
         obj->incStrong(mProcess.get());
@@ -921,7 +921,7 @@
     case BR_RELEASE:
         refs = (RefBase::weakref_type*)mIn.readInt32();
         obj = (BBinder*)mIn.readInt32();
-        LOG_ASSERT(refs->refBase() == obj,
+        ALOG_ASSERT(refs->refBase() == obj,
                    "BR_RELEASE: object %p does not match cookie %p (expected %p)",
                    refs, obj, refs->refBase());
         IF_LOG_REMOTEREFS() {
@@ -946,7 +946,7 @@
         // NOTE: This assertion is not valid, because the object may no
         // longer exist (thus the (BBinder*)cast above resulting in a different
         // memory address).
-        //LOG_ASSERT(refs->refBase() == obj,
+        //ALOG_ASSERT(refs->refBase() == obj,
         //           "BR_DECREFS: object %p does not match cookie %p (expected %p)",
         //           refs, obj, refs->refBase());
         mPendingWeakDerefs.push(refs);
@@ -958,7 +958,7 @@
          
         {
             const bool success = refs->attemptIncStrong(mProcess.get());
-            LOG_ASSERT(success && refs->refBase() == obj,
+            ALOG_ASSERT(success && refs->refBase() == obj,
                        "BR_ATTEMPT_ACQUIRE: object %p does not match cookie %p (expected %p)",
                        refs, obj, refs->refBase());
             
@@ -971,7 +971,7 @@
         {
             binder_transaction_data tr;
             result = mIn.read(&tr, sizeof(tr));
-            LOG_ASSERT(result == NO_ERROR,
+            ALOG_ASSERT(result == NO_ERROR,
                 "Not enough command data for brTRANSACTION");
             if (result != NO_ERROR) break;
             
@@ -1114,7 +1114,7 @@
     IF_LOG_COMMANDS() {
         alog << "Writing BC_FREE_BUFFER for " << data << endl;
     }
-    LOG_ASSERT(data != NULL, "Called with NULL data");
+    ALOG_ASSERT(data != NULL, "Called with NULL data");
     if (parcel != NULL) parcel->closeFileDescriptors();
     IPCThreadState* state = self();
     state->mOut.writeInt32(BC_FREE_BUFFER);
diff --git a/libs/gui/ISurfaceComposerClient.cpp b/libs/gui/ISurfaceComposerClient.cpp
index 5ebdbd9..8fe96b1 100644
--- a/libs/gui/ISurfaceComposerClient.cpp
+++ b/libs/gui/ISurfaceComposerClient.cpp
@@ -35,15 +35,6 @@
 
 // ---------------------------------------------------------------------------
 
-/* ideally AID_GRAPHICS would be in a semi-public header
- * or there would be a way to map a user/group name to its id
- */
-#ifndef AID_GRAPHICS
-#define AID_GRAPHICS 1003
-#endif
-
-// ---------------------------------------------------------------------------
-
 namespace android {
 
 enum {
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index fbabfc4..f8b4452 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -47,7 +47,6 @@
 	GraphicBuffer.cpp \
 	GraphicBufferAllocator.cpp \
 	GraphicBufferMapper.cpp \
-	GraphicLog.cpp \
 	InputTransport.cpp \
 	PixelFormat.cpp \
 	Rect.cpp \
diff --git a/libs/ui/FramebufferNativeWindow.cpp b/libs/ui/FramebufferNativeWindow.cpp
index f5ed981..d1dca0c 100644
--- a/libs/ui/FramebufferNativeWindow.cpp
+++ b/libs/ui/FramebufferNativeWindow.cpp
@@ -29,7 +29,6 @@
 
 #include <ui/Rect.h>
 #include <ui/FramebufferNativeWindow.h>
-#include <ui/GraphicLog.h>
 
 #include <EGL/egl.h>
 
@@ -211,9 +210,6 @@
     if (self->mBufferHead >= self->mNumBuffers)
         self->mBufferHead = 0;
 
-    GraphicLog& logger(GraphicLog::getInstance());
-    logger.log(GraphicLog::SF_FB_DEQUEUE_BEFORE, index);
-
     // wait for a free buffer
     while (!self->mNumFreeBuffers) {
         self->mCondition.wait(self->mutex);
@@ -224,7 +220,6 @@
 
     *buffer = self->buffers[index].get();
 
-    logger.log(GraphicLog::SF_FB_DEQUEUE_AFTER, index);
     return 0;
 }
 
@@ -235,16 +230,12 @@
     Mutex::Autolock _l(self->mutex);
 
     const int index = self->mCurrentBufferIndex;
-    GraphicLog& logger(GraphicLog::getInstance());
-    logger.log(GraphicLog::SF_FB_LOCK_BEFORE, index);
 
     // wait that the buffer we're locking is not front anymore
     while (self->front == buffer) {
         self->mCondition.wait(self->mutex);
     }
 
-    logger.log(GraphicLog::SF_FB_LOCK_AFTER, index);
-
     return NO_ERROR;
 }
 
@@ -257,13 +248,7 @@
     buffer_handle_t handle = static_cast<NativeBuffer*>(buffer)->handle;
 
     const int index = self->mCurrentBufferIndex;
-    GraphicLog& logger(GraphicLog::getInstance());
-    logger.log(GraphicLog::SF_FB_POST_BEFORE, index);
-
     int res = fb->post(fb, handle);
-
-    logger.log(GraphicLog::SF_FB_POST_AFTER, index);
-
     self->front = static_cast<NativeBuffer*>(buffer);
     self->mNumFreeBuffers++;
     self->mCondition.broadcast();
diff --git a/libs/ui/GraphicLog.cpp b/libs/ui/GraphicLog.cpp
deleted file mode 100644
index 7ba2779..0000000
--- a/libs/ui/GraphicLog.cpp
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <cutils/log.h>
-#include <cutils/properties.h>
-#include <utils/Endian.h>
-#include <utils/Timers.h>
-
-#include <ui/GraphicLog.h>
-
-namespace android {
-
-ANDROID_SINGLETON_STATIC_INSTANCE(GraphicLog)
-
-static inline
-void writeInt32(uint8_t* base, size_t& pos, int32_t value) {
-#ifdef HAVE_LITTLE_ENDIAN
-    int32_t v = value;
-#else
-    int32_t v = htole32(value);
-#endif
-    base[pos] = EVENT_TYPE_INT;
-    memcpy(&base[pos+1], &v, sizeof(int32_t));
-    pos += 1+sizeof(int32_t);
-}
-
-static inline
-void writeInt64(uint8_t* base,  size_t& pos, int64_t value) {
-#ifdef HAVE_LITTLE_ENDIAN
-    int64_t v = value;
-#else
-    int64_t v = htole64(value);
-#endif
-    base[pos] = EVENT_TYPE_LONG;
-    memcpy(&base[pos+1], &v, sizeof(int64_t));
-    pos += 1+sizeof(int64_t);
-}
-
-void GraphicLog::logImpl(int32_t tag, int32_t buffer)
-{
-    uint8_t scratch[2 + 2 + sizeof(int32_t) + sizeof(int64_t)];
-    size_t pos = 0;
-    scratch[pos++] = EVENT_TYPE_LIST;
-    scratch[pos++] = 2;
-    writeInt32(scratch, pos, buffer);
-    writeInt64(scratch, pos, ns2ms( systemTime( SYSTEM_TIME_MONOTONIC ) ));
-    android_bWriteLog(tag, scratch, sizeof(scratch));
-}
-
-void GraphicLog::logImpl(int32_t tag, int32_t identity, int32_t buffer)
-{
-    uint8_t scratch[2 + 3 + sizeof(int32_t) + sizeof(int32_t) + sizeof(int64_t)];
-    size_t pos = 0;
-    scratch[pos++] = EVENT_TYPE_LIST;
-    scratch[pos++] = 3;
-    writeInt32(scratch, pos, buffer);
-    writeInt32(scratch, pos, identity);
-    writeInt64(scratch, pos, ns2ms( systemTime( SYSTEM_TIME_MONOTONIC ) ));
-    android_bWriteLog(tag, scratch, sizeof(scratch));
-}
-
-GraphicLog::GraphicLog()
-    : mEnabled(0)
-{
-    char property[PROPERTY_VALUE_MAX];
-    if (property_get("debug.graphic_log", property, NULL) > 0) {
-        mEnabled = atoi(property);
-    }
-}
-
-void GraphicLog::setEnabled(bool enable)
-{
-    mEnabled = enable;
-}
-
-}
diff --git a/libs/utils/RefBase.cpp b/libs/utils/RefBase.cpp
index ad0939e..e80a795 100644
--- a/libs/utils/RefBase.cpp
+++ b/libs/utils/RefBase.cpp
@@ -332,7 +332,7 @@
     
     refs->addStrongRef(id);
     const int32_t c = android_atomic_inc(&refs->mStrong);
-    LOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
+    ALOG_ASSERT(c > 0, "incStrong() called on %p after last strong ref", refs);
 #if PRINT_REFS
     ALOGD("incStrong of %p from %p: cnt=%d\n", this, id, c);
 #endif
@@ -352,7 +352,7 @@
 #if PRINT_REFS
     ALOGD("decStrong of %p from %p: cnt=%d\n", this, id, c);
 #endif
-    LOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
+    ALOG_ASSERT(c >= 1, "decStrong() called on %p too many times", refs);
     if (c == 1) {
         refs->mBase->onLastStrongRef(id);
         if ((refs->mFlags&OBJECT_LIFETIME_MASK) == OBJECT_LIFETIME_STRONG) {
@@ -369,7 +369,7 @@
     
     refs->addStrongRef(id);
     const int32_t c = android_atomic_inc(&refs->mStrong);
-    LOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
+    ALOG_ASSERT(c >= 0, "forceIncStrong called on %p after ref count underflow",
                refs);
 #if PRINT_REFS
     ALOGD("forceIncStrong of %p from %p: cnt=%d\n", this, id, c);
@@ -399,7 +399,7 @@
     weakref_impl* const impl = static_cast<weakref_impl*>(this);
     impl->addWeakRef(id);
     const int32_t c = android_atomic_inc(&impl->mWeak);
-    LOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
+    ALOG_ASSERT(c >= 0, "incWeak called on %p after last weak ref", this);
 }
 
 
@@ -408,7 +408,7 @@
     weakref_impl* const impl = static_cast<weakref_impl*>(this);
     impl->removeWeakRef(id);
     const int32_t c = android_atomic_dec(&impl->mWeak);
-    LOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
+    ALOG_ASSERT(c >= 1, "decWeak called on %p too many times", this);
     if (c != 1) return;
 
     if ((impl->mFlags&OBJECT_LIFETIME_WEAK) == OBJECT_LIFETIME_STRONG) {
@@ -442,7 +442,7 @@
     weakref_impl* const impl = static_cast<weakref_impl*>(this);
     
     int32_t curCount = impl->mStrong;
-    LOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
+    ALOG_ASSERT(curCount >= 0, "attemptIncStrong called on %p after underflow",
                this);
     while (curCount > 0 && curCount != INITIAL_STRONG_VALUE) {
         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mStrong) == 0) {
@@ -503,7 +503,7 @@
     weakref_impl* const impl = static_cast<weakref_impl*>(this);
 
     int32_t curCount = impl->mWeak;
-    LOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
+    ALOG_ASSERT(curCount >= 0, "attemptIncWeak called on %p after underflow",
                this);
     while (curCount > 0) {
         if (android_atomic_cmpxchg(curCount, curCount+1, &impl->mWeak) == 0) {
diff --git a/libs/utils/String16.cpp b/libs/utils/String16.cpp
index 4ce1664..94e072f 100644
--- a/libs/utils/String16.cpp
+++ b/libs/utils/String16.cpp
@@ -112,7 +112,7 @@
 {
     size_t len = strlen16(o);
     SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
-    LOG_ASSERT(buf, "Unable to allocate shared buffer");
+    ALOG_ASSERT(buf, "Unable to allocate shared buffer");
     if (buf) {
         char16_t* str = (char16_t*)buf->data();
         strcpy16(str, o);
@@ -126,7 +126,7 @@
 String16::String16(const char16_t* o, size_t len)
 {
     SharedBuffer* buf = SharedBuffer::alloc((len+1)*sizeof(char16_t));
-    LOG_ASSERT(buf, "Unable to allocate shared buffer");
+    ALOG_ASSERT(buf, "Unable to allocate shared buffer");
     if (buf) {
         char16_t* str = (char16_t*)buf->data();
         memcpy(str, o, len*sizeof(char16_t));
diff --git a/libs/utils/String8.cpp b/libs/utils/String8.cpp
index 0bc5aff..562f026 100644
--- a/libs/utils/String8.cpp
+++ b/libs/utils/String8.cpp
@@ -80,7 +80,7 @@
 {
     if (len > 0) {
         SharedBuffer* buf = SharedBuffer::alloc(len+1);
-        LOG_ASSERT(buf, "Unable to allocate shared buffer");
+        ALOG_ASSERT(buf, "Unable to allocate shared buffer");
         if (buf) {
             char* str = (char*)buf->data();
             memcpy(str, in, len);
@@ -103,7 +103,7 @@
     }
 
     SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
-    LOG_ASSERT(buf, "Unable to allocate shared buffer");
+    ALOG_ASSERT(buf, "Unable to allocate shared buffer");
     if (!buf) {
         return getEmptyString();
     }
@@ -125,7 +125,7 @@
     }
 
     SharedBuffer* buf = SharedBuffer::alloc(bytes+1);
-    LOG_ASSERT(buf, "Unable to allocate shared buffer");
+    ALOG_ASSERT(buf, "Unable to allocate shared buffer");
     if (!buf) {
         return getEmptyString();
     }
diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp
index 4a90296..220ae3e 100644
--- a/libs/utils/VectorImpl.cpp
+++ b/libs/utils/VectorImpl.cpp
@@ -56,7 +56,7 @@
 
 VectorImpl::~VectorImpl()
 {
-    LOG_ASSERT(!mCount,
+    ALOG_ASSERT(!mCount,
         "[%p] "
         "subclasses of VectorImpl must call finish_vector()"
         " in their destructor. Leaking %d bytes.",
@@ -66,7 +66,7 @@
 
 VectorImpl& VectorImpl::operator = (const VectorImpl& rhs)
 {
-    LOG_ASSERT(mItemSize == rhs.mItemSize,
+    ALOG_ASSERT(mItemSize == rhs.mItemSize,
         "Vector<> have different types (this=%p, rhs=%p)", this, &rhs);
     if (this != &rhs) {
         release_storage();
@@ -248,7 +248,7 @@
 
 ssize_t VectorImpl::replaceAt(const void* prototype, size_t index)
 {
-    LOG_ASSERT(index<size(),
+    ALOG_ASSERT(index<size(),
         "[%p] replace: index=%d, size=%d", this, (int)index, (int)size());
 
     void* item = editItemLocation(index);
@@ -267,7 +267,7 @@
 
 ssize_t VectorImpl::removeItemsAt(size_t index, size_t count)
 {
-    LOG_ASSERT((index+count)<=size(),
+    ALOG_ASSERT((index+count)<=size(),
         "[%p] remove: index=%d, count=%d, size=%d",
                this, (int)index, (int)count, (int)size());
 
@@ -291,7 +291,7 @@
 
 void* VectorImpl::editItemLocation(size_t index)
 {
-    LOG_ASSERT(index<capacity(),
+    ALOG_ASSERT(index<capacity(),
         "[%p] editItemLocation: index=%d, capacity=%d, count=%d",
         this, (int)index, (int)capacity(), (int)mCount);
             
@@ -303,7 +303,7 @@
 
 const void* VectorImpl::itemLocation(size_t index) const
 {
-    LOG_ASSERT(index<capacity(),
+    ALOG_ASSERT(index<capacity(),
         "[%p] itemLocation: index=%d, capacity=%d, count=%d",
         this, (int)index, (int)capacity(), (int)mCount);
 
@@ -349,7 +349,7 @@
 //    ALOGV("_grow(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
 //        this, (int)where, (int)amount, (int)mCount, (int)capacity());
 
-    LOG_ASSERT(where <= mCount,
+    ALOG_ASSERT(where <= mCount,
             "[%p] _grow: where=%d, amount=%d, count=%d",
             this, (int)where, (int)amount, (int)mCount); // caller already checked
 
@@ -402,7 +402,7 @@
 //    ALOGV("_shrink(this=%p, where=%d, amount=%d) count=%d, capacity=%d",
 //        this, (int)where, (int)amount, (int)mCount, (int)capacity());
 
-    LOG_ASSERT(where + amount <= mCount,
+    ALOG_ASSERT(where + amount <= mCount,
             "[%p] _shrink: where=%d, amount=%d, count=%d",
             this, (int)where, (int)amount, (int)mCount); // caller already checked
 
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 664f258..8b37da5 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -477,6 +477,26 @@
     return result;
 }
 
+void EGLAPI eglBeginFrame(EGLDisplay dpy, EGLSurface surface) {
+    clearError();
+
+    egl_display_t const * const dp = validate_display(dpy);
+    if (!dp) {
+        return;
+    }
+
+    SurfaceRef _s(dp, surface);
+    if (!_s.get()) {
+        setError(EGL_BAD_SURFACE, EGL_FALSE);
+        return;
+    }
+
+    int64_t timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
+
+    egl_surface_t const * const s = get_surface(surface);
+    native_window_set_buffers_timestamp(s->win.get(), timestamp);
+}
+
 // ----------------------------------------------------------------------------
 // Contexts
 // ----------------------------------------------------------------------------
diff --git a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
index 5220aa4..daba3ff 100644
--- a/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
+++ b/opengl/libs/GLES_trace/src/gltrace_fixup.cpp
@@ -107,19 +107,11 @@
     fb->add_contents(fbcontents, fbsize);
 }
 
-void fixup_glTexImage2D(GLMessage *glmsg) {
-    /* void glTexImage2D(GLenum target,
-                        GLint level,
-                        GLint internalformat,
-                        GLsizei width,
-                        GLsizei height,
-                        GLint border,
-                        GLenum format,
-                        GLenum type,
-                        const GLvoid *data); 
-     */
-    GLMessage_DataType arg_width  = glmsg->args(3);
-    GLMessage_DataType arg_height = glmsg->args(4);
+/** Common fixup routing for glTexImage2D & glTexSubImage2D. */
+void fixup_glTexImage(int widthIndex, int heightIndex, GLMessage *glmsg) {
+    GLMessage_DataType arg_width  = glmsg->args(widthIndex);
+    GLMessage_DataType arg_height = glmsg->args(heightIndex);
+
     GLMessage_DataType arg_format = glmsg->args(6);
     GLMessage_DataType arg_type   = glmsg->args(7);
     GLMessage_DataType *arg_data  = glmsg->mutable_args(8);
@@ -133,21 +125,51 @@
     int bytesPerTexel = getBytesPerTexel(format, type);
 
     arg_data->set_type(GLMessage::DataType::BYTE);
-    arg_data->set_isarray(true);
     arg_data->clear_rawbytes();
 
     if (data != NULL) {
+        arg_data->set_isarray(true);
         arg_data->add_rawbytes(data, bytesPerTexel * width * height);
     } else {
-        ALOGE("fixup_glTexImage2D: image data is NULL.\n");
+        arg_data->set_isarray(false);
         arg_data->set_type(GLMessage::DataType::VOID);
-        // FIXME:
-        // This will create the texture, but it will be uninitialized. 
-        // It can later be initialized with glTexSubImage2D or by
-        // attaching an FBO to it and rendering into the FBO.
     }
 }
 
+
+void fixup_glTexImage2D(GLMessage *glmsg) {
+    /* void glTexImage2D(GLenum target,
+                        GLint level,
+                        GLint internalformat,
+                        GLsizei width,
+                        GLsizei height,
+                        GLint border,
+                        GLenum format,
+                        GLenum type,
+                        const GLvoid *data); 
+    */
+    int widthIndex = 3;
+    int heightIndex = 4;
+    fixup_glTexImage(widthIndex, heightIndex, glmsg);
+}
+
+void fixup_glTexSubImage2D(GLMessage *glmsg) {
+    /*
+    void glTexSubImage2D(GLenum target,
+                        GLint level,
+                        GLint xoffset,
+                        GLint yoffset,
+                        GLsizei width,
+                        GLsizei height,
+                        GLenum format,
+                        GLenum type,
+                        const GLvoid * data);
+    */
+    int widthIndex = 4;
+    int heightIndex = 5;
+    fixup_glTexImage(widthIndex, heightIndex, glmsg);
+}
+
 void fixup_glShaderSource(GLMessage *glmsg) {
     /* void glShaderSource(GLuint shader, GLsizei count, const GLchar** string, 
                                     const GLint* length) */
@@ -218,6 +240,14 @@
     fixup_GenericIntArray(1, n, glmsg);
 }
 
+void fixup_glDeleteGeneric(GLMessage *glmsg) {
+    /* void glDelete*(GLsizei n, GLuint *buffers); */
+    GLMessage_DataType arg_n  = glmsg->args(0);
+    GLsizei n = arg_n.intvalue(0);
+
+    fixup_GenericIntArray(1, n, glmsg);
+}
+
 void fixup_glGetBooleanv(GLMessage *glmsg) {
     /* void glGetBooleanv(GLenum pname, GLboolean *params); */
     GLMessage_DataType *arg_params = glmsg->mutable_args(1);
@@ -250,10 +280,16 @@
 
     // do any custom message dependent processing
     switch (glmsg->function()) {
-    case GLMessage::glGenBuffers:        /* void glGenBuffers(GLsizei n, GLuint * buffers); */
-    case GLMessage::glGenFramebuffers:   /* void glGenFramebuffers(GLsizei n, GLuint * buffers); */
-    case GLMessage::glGenRenderbuffers:  /* void glGenFramebuffers(GLsizei n, GLuint * buffers); */
-    case GLMessage::glGenTextures:       /* void glGenTextures(GLsizei n, GLuint * buffers); */
+    case GLMessage::glDeleteBuffers:      /* glDeleteBuffers(GLsizei n, GLuint *buffers); */
+    case GLMessage::glDeleteFramebuffers: /* glDeleteFramebuffers(GLsizei n, GLuint *buffers); */
+    case GLMessage::glDeleteRenderbuffers:/* glDeleteRenderbuffers(GLsizei n, GLuint *buffers); */
+    case GLMessage::glDeleteTextures:     /* glDeleteTextures(GLsizei n, GLuint *textures); */
+        fixup_glDeleteGeneric(glmsg);
+        break;
+    case GLMessage::glGenBuffers:        /* void glGenBuffers(GLsizei n, GLuint *buffers); */
+    case GLMessage::glGenFramebuffers:   /* void glGenFramebuffers(GLsizei n, GLuint *buffers); */
+    case GLMessage::glGenRenderbuffers:  /* void glGenFramebuffers(GLsizei n, GLuint *buffers); */
+    case GLMessage::glGenTextures:       /* void glGenTextures(GLsizei n, GLuint *textures); */
         fixup_glGenGeneric(glmsg);
         break;
     case GLMessage::glGetAttribLocation:  
@@ -287,6 +323,11 @@
             fixup_glTexImage2D(glmsg);
         }
         break;
+    case GLMessage::glTexSubImage2D:
+        if (context->getGlobalTraceState()->shouldCollectTextureDataOnGlTexImage()) {
+            fixup_glTexSubImage2D(glmsg);
+        }
+        break;
     case GLMessage::glShaderSource:
         fixup_glShaderSource(glmsg);
         break;
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
index cf131b1..986aec5 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.cpp
@@ -350,15 +350,28 @@
 }
 
 // this needs to be thread safe
-nsecs_t DisplayHardware::waitForVSync() const {
+nsecs_t DisplayHardware::waitForRefresh() const {
     nsecs_t timestamp;
     if (mVSync.wait(&timestamp) < 0) {
         // vsync not supported!
         usleep( getDelayToNextVSyncUs(&timestamp) );
     }
+    mLastHwVSync = timestamp; // FIXME: Not thread safe
     return timestamp;
 }
 
+nsecs_t DisplayHardware::getRefreshTimestamp() const {
+    // this returns the last refresh timestamp.
+    // if the last one is not available, we estimate it based on
+    // the refresh period and whatever closest timestamp we have.
+    nsecs_t now = systemTime();
+    return now - ((now - mLastHwVSync) %  mRefreshPeriod);
+}
+
+nsecs_t DisplayHardware::getRefreshPeriod() const {
+    return mRefreshPeriod;
+}
+
 int32_t DisplayHardware::getDelayToNextVSyncUs(nsecs_t* timestamp) const {
     Mutex::Autolock _l(mFakeVSyncMutex);
     const nsecs_t period = mRefreshPeriod;
@@ -384,10 +397,6 @@
     return mNativeWindow->compositionComplete();
 }
 
-int DisplayHardware::getCurrentBufferIndex() const {
-    return mNativeWindow->getCurrentBufferIndex();
-}
-
 void DisplayHardware::flip(const Region& dirty) const
 {
     checkGLErrors();
diff --git a/services/surfaceflinger/DisplayHardware/DisplayHardware.h b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
index 45d4b45..02be4dc 100644
--- a/services/surfaceflinger/DisplayHardware/DisplayHardware.h
+++ b/services/surfaceflinger/DisplayHardware/DisplayHardware.h
@@ -76,7 +76,9 @@
     uint32_t    getMaxViewportDims() const;
 
     // waits for the next vsync and returns the timestamp of when it happened
-    nsecs_t        waitForVSync() const;
+    nsecs_t     waitForRefresh() const;
+    nsecs_t     getRefreshPeriod() const;
+    nsecs_t     getRefreshTimestamp() const;
 
     uint32_t getPageFlipCount() const;
     EGLDisplay getEGLDisplay() const { return mDisplay; }
@@ -93,9 +95,6 @@
     }
     inline Rect bounds() const { return getBounds(); }
 
-    // only for debugging
-    int getCurrentBufferIndex() const;
-
 private:
     void init(uint32_t displayIndex) __attribute__((noinline));
     void fini() __attribute__((noinline));
@@ -122,6 +121,7 @@
     mutable Mutex   mFakeVSyncMutex;
     mutable nsecs_t mNextFakeVSync;
     nsecs_t         mRefreshPeriod;
+    mutable nsecs_t mLastHwVSync;
 
     HWComposer*     mHwc;
 
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index 9245781..6796d7d 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -102,32 +102,22 @@
 
     nsecs_t timestamp;
     DisplayEventReceiver::Event vsync;
-    KeyedVector< wp<DisplayEventConnection>, ConnectionInfo > displayEventConnections;
+    Vector< wp<DisplayEventConnection> > displayEventConnections;
 
     { // scope for the lock
         Mutex::Autolock _l(mLock);
         do {
-            // wait for listeners
+            // see if we need to wait for the VSYNC at all
             do {
                 bool waitForNextVsync = false;
                 size_t count = mDisplayEventConnections.size();
                 for (size_t i=0 ; i<count ; i++) {
                     const ConnectionInfo& info(
                             mDisplayEventConnections.valueAt(i));
-                    if (info.count >= 1) {
-                        // continuous mode
+                    if (info.count >= 0) {
+                        // at least one continuous mode or active one-shot event
                         waitForNextVsync = true;
-                    } else {
-                        // one-shot event
-                        if (info.count >= -1) {
-                            ConnectionInfo& info(
-                                    mDisplayEventConnections.editValueAt(i));
-                            info.count--;
-                            if (info.count == -1) {
-                                // fired this time around
-                                waitForNextVsync = true;
-                            }
-                        }
+                        break;
                     }
                 }
 
@@ -137,51 +127,53 @@
                 mCondition.wait(mLock);
             } while(true);
 
-            // wait for vsync
+            // at least one listener requested VSYNC
             mLock.unlock();
-            timestamp = mHw.waitForVSync();
+            timestamp = mHw.waitForRefresh();
             mLock.lock();
             mDeliveredEvents++;
 
-            // make sure we still have some listeners
-        } while (!mDisplayEventConnections.size());
+            // now see if we still need to report this VSYNC event
+            bool reportVsync = false;
+            size_t count = mDisplayEventConnections.size();
+            for (size_t i=0 ; i<count ; i++) {
+                const ConnectionInfo& info(
+                        mDisplayEventConnections.valueAt(i));
+                if (info.count >= 1) {
+                    if (info.count==1 || (mDeliveredEvents % info.count) == 0) {
+                        // continuous event, and time to report it
+                        reportVsync = true;
+                    }
+                } else if (info.count >= -1) {
+                    ConnectionInfo& info(
+                            mDisplayEventConnections.editValueAt(i));
+                    if (info.count == 0) {
+                        // fired this time around
+                        reportVsync = true;
+                    }
+                    info.count--;
+                }
+                if (reportVsync) {
+                    displayEventConnections.add(mDisplayEventConnections.keyAt(i));
+                }
+            }
+
+            if (reportVsync) {
+                break;
+            }
+        } while (true);
 
         // dispatch vsync events to listeners...
         vsync.header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
         vsync.header.timestamp = timestamp;
         vsync.vsync.count = mDeliveredEvents;
-
-        // make a copy of our connection list, so we can
-        // dispatch events without holding mLock
-        displayEventConnections = mDisplayEventConnections;
     }
 
     const size_t count = displayEventConnections.size();
     for (size_t i=0 ; i<count ; i++) {
-        sp<DisplayEventConnection> conn(displayEventConnections.keyAt(i).promote());
+        sp<DisplayEventConnection> conn(displayEventConnections[i].promote());
         // make sure the connection didn't die
         if (conn != NULL) {
-
-            const ConnectionInfo& info(
-                    displayEventConnections.valueAt(i));
-
-            if ((info.count > 1) && (mDeliveredEvents % info.count)) {
-                // continuous event, but not time to send this event yet
-                continue;
-            } else if (info.count < -1) {
-                // disabled event
-                continue;
-            } else if (info.count == 0) {
-                // impossible by construction. but we prefer to be safe.
-                continue;
-            }
-
-            // here, either:
-            // count = -1 : one-shot scheduled this time around
-            // count =  1 : continuous not rate-limited
-            // count >  1 : continuous, rate-limited
-            // Note: count == 0 is not possible by construction
-
             status_t err = conn->postEvent(vsync);
             if (err == -EAGAIN || err == -EWOULDBLOCK) {
                 // The destination doesn't accept events anymore, it's probably
@@ -193,12 +185,12 @@
                 // handle any other error on the pipe as fatal. the only
                 // reasonable thing to do is to clean-up this connection.
                 // The most common error we'll get here is -EPIPE.
-                removeDisplayEventConnection(displayEventConnections.keyAt(i));
+                removeDisplayEventConnection(displayEventConnections[i]);
             }
         } else {
             // somehow the connection is dead, but we still have it in our list
             // just clean the list.
-            removeDisplayEventConnection(displayEventConnections.keyAt(i));
+            removeDisplayEventConnection(displayEventConnections[i]);
         }
     }
 
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index d4c4b1f..a294281 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -38,6 +38,7 @@
 #include "Layer.h"
 #include "SurfaceFlinger.h"
 #include "SurfaceTextureLayer.h"
+#include <math.h>
 
 #define DEBUG_RESIZE    0
 
@@ -54,6 +55,8 @@
         mCurrentTransform(0),
         mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
         mCurrentOpacity(true),
+        mFrameLatencyNeeded(false),
+        mFrameLatencyOffset(0),
         mFormat(PIXEL_FORMAT_NONE),
         mGLExtensions(GLExtensions::getInstance()),
         mOpaqueLayer(true),
@@ -65,6 +68,17 @@
     glGenTextures(1, &mTextureName);
 }
 
+void Layer::onLayerDisplayed() {
+    if (mFrameLatencyNeeded) {
+        const DisplayHardware& hw(graphicPlane(0).displayHardware());
+        mFrameStats[mFrameLatencyOffset].timestamp = mSurfaceTexture->getTimestamp();
+        mFrameStats[mFrameLatencyOffset].set = systemTime();
+        mFrameStats[mFrameLatencyOffset].vsync = hw.getRefreshTimestamp();
+        mFrameLatencyOffset = (mFrameLatencyOffset + 1) % 128;
+        mFrameLatencyNeeded = false;
+    }
+}
+
 void Layer::onFirstRef()
 {
     LayerBaseClient::onFirstRef();
@@ -408,6 +422,7 @@
 
         // update the active buffer
         mActiveBuffer = mSurfaceTexture->getCurrentBuffer();
+        mFrameLatencyNeeded = true;
 
         const Rect crop(mSurfaceTexture->getCurrentCrop());
         const uint32_t transform(mSurfaceTexture->getCurrentTransform());
@@ -538,11 +553,33 @@
 
     result.append(buffer);
 
+    LayerBase::dumpStats(result, buffer, SIZE);
+
     if (mSurfaceTexture != 0) {
         mSurfaceTexture->dump(result, "            ", buffer, SIZE);
     }
 }
 
+void Layer::dumpStats(String8& result, char* buffer, size_t SIZE) const
+{
+    LayerBaseClient::dumpStats(result, buffer, SIZE);
+    const size_t o = mFrameLatencyOffset;
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    const nsecs_t period = hw.getRefreshPeriod();
+    result.appendFormat("%lld\n", period);
+    for (size_t i=0 ; i<128 ; i++) {
+        const size_t index = (o+i) % 128;
+        const nsecs_t time_app   = mFrameStats[index].timestamp;
+        const nsecs_t time_set   = mFrameStats[index].set;
+        const nsecs_t time_vsync = mFrameStats[index].vsync;
+        result.appendFormat("%lld\t%lld\t%lld\n",
+                time_app,
+                time_vsync,
+                time_set);
+    }
+    result.append("\n");
+}
+
 uint32_t Layer::getEffectiveUsage(uint32_t usage) const
 {
     // TODO: should we do something special if mSecure is set?
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2b9471b..b3fa5e7 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -34,6 +34,7 @@
 #include "LayerBase.h"
 #include "SurfaceTextureLayer.h"
 #include "Transform.h"
+#include <utils/Timers.h>
 
 namespace android {
 
@@ -78,12 +79,15 @@
     // LayerBaseClient interface
     virtual wp<IBinder> getSurfaceTextureBinder() const;
 
+    virtual void onLayerDisplayed();
+
     // only for debugging
     inline const sp<GraphicBuffer>& getActiveBuffer() const { return mActiveBuffer; }
 
 protected:
     virtual void onFirstRef();
     virtual void dump(String8& result, char* scratch, size_t size) const;
+    virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const;
 
 private:
     friend class SurfaceTextureLayer;
@@ -110,6 +114,16 @@
     uint32_t mCurrentTransform;
     uint32_t mCurrentScalingMode;
     bool mCurrentOpacity;
+    bool mFrameLatencyNeeded;
+    int mFrameLatencyOffset;
+    struct Statistics {
+        Statistics() : timestamp(0), set(0), vsync(0) { }
+        nsecs_t timestamp;  // buffer timestamp
+        nsecs_t set;        // buffer displayed timestamp
+        nsecs_t vsync;      // vsync immediately before set
+    };
+    // protected by mLock
+    Statistics mFrameStats[128];
 
     // constants
     PixelFormat mFormat;
@@ -121,9 +135,6 @@
     bool mSecure;         // no screenshots
     bool mProtectedByApp; // application requires protected path to external sink
     Region mPostedDirtyRegion;
-
-    // binder thread, transaction thread
-    mutable Mutex mLock;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerBase.cpp b/services/surfaceflinger/LayerBase.cpp
index 37879f1..1e2c4cb 100644
--- a/services/surfaceflinger/LayerBase.cpp
+++ b/services/surfaceflinger/LayerBase.cpp
@@ -471,6 +471,9 @@
 void LayerBase::dump(String8& result, char* buffer, size_t SIZE) const
 {
     const Layer::State& s(drawingState());
+    s.transparentRegion.dump(result, "transparentRegion");
+    transparentRegionScreen.dump(result, "transparentRegionScreen");
+    visibleRegionScreen.dump(result, "visibleRegionScreen");
     snprintf(buffer, SIZE,
             "+ %s %p (%s)\n"
             "      "
@@ -491,6 +494,9 @@
     LayerBase::dump(result, scratch, size);
 }
 
+void LayerBase::dumpStats(String8& result, char* scratch, size_t SIZE) const
+{
+}
 
 // ---------------------------------------------------------------------------
 
diff --git a/services/surfaceflinger/LayerBase.h b/services/surfaceflinger/LayerBase.h
index 7f62145..03d2cc6 100644
--- a/services/surfaceflinger/LayerBase.h
+++ b/services/surfaceflinger/LayerBase.h
@@ -205,10 +205,13 @@
     /** called with the state lock when the surface is removed from the
      *  current list */
     virtual void onRemoved() { };
-    
+
+    virtual void onLayerDisplayed() { };
+
     /** always call base class first */
     virtual void dump(String8& result, char* scratch, size_t size) const;
     virtual void shortDump(String8& result, char* scratch, size_t size) const;
+    virtual void dumpStats(String8& result, char* buffer, size_t SIZE) const;
 
 
     enum { // flags for doTransaction()
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index bbb30b0..883b642 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -41,7 +41,6 @@
 #include <utils/StopWatch.h>
 
 #include <ui/GraphicBufferAllocator.h>
-#include <ui/GraphicLog.h>
 #include <ui/PixelFormat.h>
 
 #include <pixelflinger/pixelflinger.h>
@@ -60,15 +59,9 @@
 #include "DisplayHardware/DisplayHardware.h"
 #include "DisplayHardware/HWComposer.h"
 
+#include <private/android_filesystem_config.h>
 #include <private/surfaceflinger/SharedBufferStack.h>
 
-/* ideally AID_GRAPHICS would be in a semi-public header
- * or there would be a way to map a user/group name to its id
- */
-#ifndef AID_GRAPHICS
-#define AID_GRAPHICS 1003
-#endif
-
 #define EGL_VERSION_HW_ANDROID  0x3143
 
 #define DISPLAY_COUNT       1
@@ -431,25 +424,14 @@
     const DisplayHardware& hw(graphicPlane(0).displayHardware());
     if (CC_LIKELY(hw.canDraw())) {
         // repaint the framebuffer (if needed)
-
-        const int index = hw.getCurrentBufferIndex();
-        GraphicLog& logger(GraphicLog::getInstance());
-
-        logger.log(GraphicLog::SF_REPAINT, index);
         handleRepaint();
-
         // inform the h/w that we're done compositing
-        logger.log(GraphicLog::SF_COMPOSITION_COMPLETE, index);
         hw.compositionComplete();
-
-        logger.log(GraphicLog::SF_SWAP_BUFFERS, index);
         postFramebuffer();
-
-        logger.log(GraphicLog::SF_REPAINT_DONE, index);
     } else {
         // pretend we did the post
         hw.compositionComplete();
-        hw.waitForVSync();
+        hw.waitForRefresh();
     }
     return true;
 }
@@ -463,6 +445,12 @@
     const nsecs_t now = systemTime();
     mDebugInSwapBuffers = now;
     hw.flip(mSwapRegion);
+
+    size_t numLayers = mVisibleLayersSortedByZ.size();
+    for (size_t i = 0; i < numLayers; i++) {
+        mVisibleLayersSortedByZ[i]->onLayerDisplayed();
+    }
+
     mLastSwapBufferTime = systemTime() - now;
     mDebugInSwapBuffers = 0;
     mSwapRegion.clear();
@@ -1097,23 +1085,6 @@
     }
 }
 
-void SurfaceFlinger::debugShowFPS() const
-{
-    static int mFrameCount;
-    static int mLastFrameCount = 0;
-    static nsecs_t mLastFpsTime = 0;
-    static float mFps = 0;
-    mFrameCount++;
-    nsecs_t now = systemTime();
-    nsecs_t diff = now - mLastFpsTime;
-    if (diff > ms2ns(250)) {
-        mFps =  ((mFrameCount - mLastFrameCount) * float(s2ns(1))) / diff;
-        mLastFpsTime = now;
-        mLastFrameCount = mFrameCount;
-    }
-    // XXX: mFPS has the value we want
- }
-
 status_t SurfaceFlinger::addLayer(const sp<LayerBase>& layer)
 {
     Mutex::Autolock _l(mStateLock);
@@ -1498,14 +1469,6 @@
                 IPCThreadState::self()->getCallingUid());
         result.append(buffer);
     } else {
-
-        // figure out if we're stuck somewhere
-        const nsecs_t now = systemTime();
-        const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
-        const nsecs_t inTransaction(mDebugInTransaction);
-        nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
-        nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
-
         // Try to get the main lock, but don't insist if we can't
         // (this would indicate SF is stuck, but we want to be able to
         // print something in dumpsys).
@@ -1521,111 +1484,20 @@
             result.append(buffer);
         }
 
-        /*
-         * Dump the visible layer list
-         */
-        const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
-        const size_t count = currentLayers.size();
-        snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count);
-        result.append(buffer);
-        for (size_t i=0 ; i<count ; i++) {
-            const sp<LayerBase>& layer(currentLayers[i]);
-            layer->dump(result, buffer, SIZE);
-            const Layer::State& s(layer->drawingState());
-            s.transparentRegion.dump(result, "transparentRegion");
-            layer->transparentRegionScreen.dump(result, "transparentRegionScreen");
-            layer->visibleRegionScreen.dump(result, "visibleRegionScreen");
+        bool dumpAll = true;
+        size_t index = 0;
+        if (args.size()) {
+            dumpAll = false;
+            if (args[index] == String16("--latency")) {
+                index++;
+                dumpStatsLocked(args, index, result, buffer, SIZE);
+            }
         }
 
-        /*
-         * Dump the layers in the purgatory
-         */
-
-        const size_t purgatorySize = mLayerPurgatory.size();
-        snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize);
-        result.append(buffer);
-        for (size_t i=0 ; i<purgatorySize ; i++) {
-            const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
-            layer->shortDump(result, buffer, SIZE);
+        if (dumpAll) {
+            dumpAllLocked(result, buffer, SIZE);
         }
 
-        /*
-         * Dump SurfaceFlinger global state
-         */
-
-        snprintf(buffer, SIZE, "SurfaceFlinger global state:\n");
-        result.append(buffer);
-
-        const GLExtensions& extensions(GLExtensions::getInstance());
-        snprintf(buffer, SIZE, "GLES: %s, %s, %s\n",
-                extensions.getVendor(),
-                extensions.getRenderer(),
-                extensions.getVersion());
-        result.append(buffer);
-
-        snprintf(buffer, SIZE, "EGL : %s\n",
-                eglQueryString(graphicPlane(0).getEGLDisplay(),
-                        EGL_VERSION_HW_ANDROID));
-        result.append(buffer);
-
-        snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension());
-        result.append(buffer);
-
-        mWormholeRegion.dump(result, "WormholeRegion");
-        const DisplayHardware& hw(graphicPlane(0).displayHardware());
-        snprintf(buffer, SIZE,
-                "  orientation=%d, canDraw=%d\n",
-                mCurrentState.orientation, hw.canDraw());
-        result.append(buffer);
-        snprintf(buffer, SIZE,
-                "  last eglSwapBuffers() time: %f us\n"
-                "  last transaction time     : %f us\n"
-                "  refresh-rate              : %f fps\n"
-                "  x-dpi                     : %f\n"
-                "  y-dpi                     : %f\n",
-                mLastSwapBufferTime/1000.0,
-                mLastTransactionTime/1000.0,
-                hw.getRefreshRate(),
-                hw.getDpiX(),
-                hw.getDpiY());
-        result.append(buffer);
-
-        if (inSwapBuffersDuration || !locked) {
-            snprintf(buffer, SIZE, "  eglSwapBuffers time: %f us\n",
-                    inSwapBuffersDuration/1000.0);
-            result.append(buffer);
-        }
-
-        if (inTransactionDuration || !locked) {
-            snprintf(buffer, SIZE, "  transaction time: %f us\n",
-                    inTransactionDuration/1000.0);
-            result.append(buffer);
-        }
-
-        /*
-         * VSYNC state
-         */
-        mEventThread->dump(result, buffer, SIZE);
-
-        /*
-         * Dump HWComposer state
-         */
-        HWComposer& hwc(hw.getHwComposer());
-        snprintf(buffer, SIZE, "h/w composer state:\n");
-        result.append(buffer);
-        snprintf(buffer, SIZE, "  h/w composer %s and %s\n",
-                hwc.initCheck()==NO_ERROR ? "present" : "not present",
-                (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled");
-        result.append(buffer);
-        hwc.dump(result, buffer, SIZE, mVisibleLayersSortedByZ);
-
-        /*
-         * Dump gralloc state
-         */
-        const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
-        alloc.dump(result);
-        hw.dump(result);
-
         if (locked) {
             mStateLock.unlock();
         }
@@ -1634,6 +1506,137 @@
     return NO_ERROR;
 }
 
+void SurfaceFlinger::dumpStatsLocked(const Vector<String16>& args, size_t& index,
+        String8& result, char* buffer, size_t SIZE) const
+{
+    String8 name;
+    if (index < args.size()) {
+        name = String8(args[index]);
+        index++;
+    }
+
+    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+    const size_t count = currentLayers.size();
+    for (size_t i=0 ; i<count ; i++) {
+        const sp<LayerBase>& layer(currentLayers[i]);
+        if (name.isEmpty()) {
+            snprintf(buffer, SIZE, "%s\n", layer->getName().string());
+            result.append(buffer);
+        }
+        if (name.isEmpty() || (name == layer->getName())) {
+            layer->dumpStats(result, buffer, SIZE);
+        }
+    }
+}
+
+void SurfaceFlinger::dumpAllLocked(
+        String8& result, char* buffer, size_t SIZE) const
+{
+    // figure out if we're stuck somewhere
+    const nsecs_t now = systemTime();
+    const nsecs_t inSwapBuffers(mDebugInSwapBuffers);
+    const nsecs_t inTransaction(mDebugInTransaction);
+    nsecs_t inSwapBuffersDuration = (inSwapBuffers) ? now-inSwapBuffers : 0;
+    nsecs_t inTransactionDuration = (inTransaction) ? now-inTransaction : 0;
+
+    /*
+     * Dump the visible layer list
+     */
+    const LayerVector& currentLayers = mCurrentState.layersSortedByZ;
+    const size_t count = currentLayers.size();
+    snprintf(buffer, SIZE, "Visible layers (count = %d)\n", count);
+    result.append(buffer);
+    for (size_t i=0 ; i<count ; i++) {
+        const sp<LayerBase>& layer(currentLayers[i]);
+        layer->dump(result, buffer, SIZE);
+    }
+
+    /*
+     * Dump the layers in the purgatory
+     */
+
+    const size_t purgatorySize = mLayerPurgatory.size();
+    snprintf(buffer, SIZE, "Purgatory state (%d entries)\n", purgatorySize);
+    result.append(buffer);
+    for (size_t i=0 ; i<purgatorySize ; i++) {
+        const sp<LayerBase>& layer(mLayerPurgatory.itemAt(i));
+        layer->shortDump(result, buffer, SIZE);
+    }
+
+    /*
+     * Dump SurfaceFlinger global state
+     */
+
+    snprintf(buffer, SIZE, "SurfaceFlinger global state:\n");
+    result.append(buffer);
+
+    const GLExtensions& extensions(GLExtensions::getInstance());
+    snprintf(buffer, SIZE, "GLES: %s, %s, %s\n",
+            extensions.getVendor(),
+            extensions.getRenderer(),
+            extensions.getVersion());
+    result.append(buffer);
+
+    snprintf(buffer, SIZE, "EGL : %s\n",
+            eglQueryString(graphicPlane(0).getEGLDisplay(),
+                    EGL_VERSION_HW_ANDROID));
+    result.append(buffer);
+
+    snprintf(buffer, SIZE, "EXTS: %s\n", extensions.getExtension());
+    result.append(buffer);
+
+    mWormholeRegion.dump(result, "WormholeRegion");
+    const DisplayHardware& hw(graphicPlane(0).displayHardware());
+    snprintf(buffer, SIZE,
+            "  orientation=%d, canDraw=%d\n",
+            mCurrentState.orientation, hw.canDraw());
+    result.append(buffer);
+    snprintf(buffer, SIZE,
+            "  last eglSwapBuffers() time: %f us\n"
+            "  last transaction time     : %f us\n"
+            "  refresh-rate              : %f fps\n"
+            "  x-dpi                     : %f\n"
+            "  y-dpi                     : %f\n",
+            mLastSwapBufferTime/1000.0,
+            mLastTransactionTime/1000.0,
+            hw.getRefreshRate(),
+            hw.getDpiX(),
+            hw.getDpiY());
+    result.append(buffer);
+
+    snprintf(buffer, SIZE, "  eglSwapBuffers time: %f us\n",
+            inSwapBuffersDuration/1000.0);
+    result.append(buffer);
+
+    snprintf(buffer, SIZE, "  transaction time: %f us\n",
+            inTransactionDuration/1000.0);
+    result.append(buffer);
+
+    /*
+     * VSYNC state
+     */
+    mEventThread->dump(result, buffer, SIZE);
+
+    /*
+     * Dump HWComposer state
+     */
+    HWComposer& hwc(hw.getHwComposer());
+    snprintf(buffer, SIZE, "h/w composer state:\n");
+    result.append(buffer);
+    snprintf(buffer, SIZE, "  h/w composer %s and %s\n",
+            hwc.initCheck()==NO_ERROR ? "present" : "not present",
+                    (mDebugDisableHWC || mDebugRegion) ? "disabled" : "enabled");
+    result.append(buffer);
+    hwc.dump(result, buffer, SIZE, mVisibleLayersSortedByZ);
+
+    /*
+     * Dump gralloc state
+     */
+    const GraphicBufferAllocator& alloc(GraphicBufferAllocator::get());
+    alloc.dump(result);
+    hw.dump(result);
+}
+
 status_t SurfaceFlinger::onTransact(
     uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
 {
@@ -1707,11 +1710,6 @@
                 setTransactionFlags(eTransactionNeeded|eTraversalNeeded);
                 return NO_ERROR;
             }
-            case 1006:{ // enable/disable GraphicLog
-                int enabled = data.readInt32();
-                GraphicLog::getInstance().setEnabled(enabled);
-                return NO_ERROR;
-            }
             case 1008:  // toggle use of hw composer
                 n = data.readInt32();
                 mDebugDisableHWC = n ? 1 : 0;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index ffd3ac9..c976e5a 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -335,9 +335,11 @@
             status_t electronBeamOnAnimationImplLocked();
 
             void        debugFlashRegions();
-            void        debugShowFPS() const;
             void        drawWormhole() const;
            
+            void dumpStatsLocked(const Vector<String16>& args, size_t& index,
+                    String8& result, char* buffer, size_t SIZE) const;
+            void dumpAllLocked(String8& result, char* buffer, size_t SIZE) const;
 
     mutable     MessageQueue    mEventQueue;