Merge "Fix deadlock when cleaning objects in eglTerminate"
diff --git a/include/utils/Tokenizer.h b/include/utils/Tokenizer.h
index c7db5fb..bb25f37 100644
--- a/include/utils/Tokenizer.h
+++ b/include/utils/Tokenizer.h
@@ -28,7 +28,8 @@
  * A simple tokenizer for loading and parsing ASCII text files line by line.
  */
 class Tokenizer {
-    Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, size_t length);
+    Tokenizer(const String8& filename, FileMap* fileMap, char* buffer,
+            bool ownBuffer, size_t length);
 
 public:
     ~Tokenizer();
@@ -42,6 +43,15 @@
     static status_t open(const String8& filename, Tokenizer** outTokenizer);
 
     /**
+     * Prepares to tokenize the contents of a string.
+     *
+     * Returns NO_ERROR and a tokenizer for the string, if successful.
+     * Otherwise returns an error and sets outTokenizer to NULL.
+     */
+    static status_t fromContents(const String8& filename,
+            const char* contents, Tokenizer** outTokenizer);
+
+    /**
      * Returns true if at the end of the file.
      */
     inline bool isEof() const { return mCurrent == getEnd(); }
@@ -111,6 +121,7 @@
     String8 mFilename;
     FileMap* mFileMap;
     char* mBuffer;
+    bool mOwnBuffer;
     size_t mLength;
 
     const char* mCurrent;
diff --git a/include/utils/Trace.h b/include/utils/Trace.h
index a2429c0..637c146 100644
--- a/include/utils/Trace.h
+++ b/include/utils/Trace.h
@@ -45,7 +45,8 @@
 #define ATRACE_TAG_GRAPHICS (1<<1)
 #define ATRACE_TAG_INPUT    (1<<2)
 #define ATRACE_TAG_VIEW     (1<<3)
-#define ATRACE_TAG_LAST     ATRACE_TAG_VIEW
+#define ATRACE_TAG_WEBVIEW  (1<<4)
+#define ATRACE_TAG_LAST     ATRACE_TAG_WEBVIEW
 
 #define ATRACE_TAG_VALID_MASK ((ATRACE_TAG_LAST - 1) | ATRACE_TAG_LAST)
 
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 9fa412c..5399e52 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -73,10 +73,11 @@
 
 sp<ProcessState> ProcessState::self()
 {
-    if (gProcess != NULL) return gProcess;
-    
-    AutoMutex _l(gProcessMutex);
-    if (gProcess == NULL) gProcess = new ProcessState;
+    Mutex::Autolock _l(gProcessMutex);
+    if (gProcess != NULL) {
+        return gProcess;
+    }
+    gProcess = new ProcessState;
     return gProcess;
 }
 
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 01d08b7..ece0494 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -57,9 +57,12 @@
 #define ST_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
 
 #define ATRACE_BUFFER_INDEX(index)                                            \
-    char ___traceBuf[1024];                                                   \
-    snprintf(___traceBuf, 1024, "%s: %d", mConsumerName.string(), (index));   \
-    android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf);
+    if (ATRACE_ENABLED()) {                                                   \
+        char ___traceBuf[1024];                                               \
+        snprintf(___traceBuf, 1024, "%s: %d", mConsumerName.string(),         \
+                (index));                                                     \
+        android::ScopedTrace ___bufTracer(ATRACE_TAG, ___traceBuf);           \
+    }
 
 namespace android {
 
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 0fa9ca1..a6ee971 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -344,6 +344,18 @@
         glDeleteTextures(1, &mTexName);
     }
 
+    // Because we're giving up the EGLDisplay we need to free all the EGLImages
+    // that are associated with it.  They'll be recreated when the
+    // SurfaceTexture gets attached to a new OpenGL ES context (and thus gets a
+    // new EGLDisplay).
+    for (int i =0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+        EGLImageKHR img = mEGLSlots[i].mEglImage;
+        if (img != EGL_NO_IMAGE_KHR) {
+            eglDestroyImageKHR(mEglDisplay, img);
+            mEGLSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+        }
+    }
+
     mEglDisplay = EGL_NO_DISPLAY;
     mEglContext = EGL_NO_CONTEXT;
     mAttached = false;
@@ -542,28 +554,16 @@
         // decoder, camera, etc.) would simply not use a crop rectangle (or at
         // least not tell the framework about it) so that the GPU can do the
         // correct edge behavior.
-        int xshrink = 0, yshrink = 0;
-        if (mCurrentCrop.left > 0) {
-            tx = float(mCurrentCrop.left + 1) / float(buf->getWidth());
-            xshrink++;
-        } else {
-            tx = 0.0f;
-        }
-        if (mCurrentCrop.right < int32_t(buf->getWidth())) {
-            xshrink++;
-        }
-        if (mCurrentCrop.bottom < int32_t(buf->getHeight())) {
-            ty = (float(buf->getHeight() - mCurrentCrop.bottom) + 1.0f) /
-                    float(buf->getHeight());
-            yshrink++;
-        } else {
-            ty = 0.0f;
-        }
-        if (mCurrentCrop.top > 0) {
-            yshrink++;
-        }
-        sx = float(mCurrentCrop.width() - xshrink) / float(buf->getWidth());
-        sy = float(mCurrentCrop.height() - yshrink) / float(buf->getHeight());
+        const float shrinkAmount = 1.0f; // the amount that each edge is shrunk
+
+        tx = (float(mCurrentCrop.left) + shrinkAmount) /
+                float(buf->getWidth());
+        ty = (float(buf->getHeight() - mCurrentCrop.bottom) +
+                shrinkAmount) / float(buf->getHeight());
+        sx = (float(mCurrentCrop.width()) - (2.0f * shrinkAmount)) /
+                float(buf->getWidth());
+        sy = (float(mCurrentCrop.height()) - (2.0f * shrinkAmount)) /
+                float(buf->getHeight());
     } else {
         tx = 0.0f;
         ty = 0.0f;
@@ -680,13 +680,12 @@
     if (slotIndex == mCurrentTexture) {
         mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
     }
-    if (mEGLSlots[slotIndex].mEglImage != EGL_NO_IMAGE_KHR) {
-        EGLImageKHR img = mEGLSlots[slotIndex].mEglImage;
-        if (img != EGL_NO_IMAGE_KHR) {
-            eglDestroyImageKHR(mEglDisplay, img);
-        }
-        mEGLSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
+    EGLImageKHR img = mEGLSlots[slotIndex].mEglImage;
+    if (img != EGL_NO_IMAGE_KHR) {
+        ST_LOGV("destroying EGLImage dpy=%p img=%p", mEglDisplay, img);
+        eglDestroyImageKHR(mEglDisplay, img);
     }
+    mEGLSlots[slotIndex].mEglImage = EGL_NO_IMAGE_KHR;
 }
 
 void SurfaceTexture::abandon() {
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index aa1f94e..b576ca5 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -580,13 +580,13 @@
 
     // This accounts for the 1 texel shrink for each edge that's included in the
     // transform matrix to avoid texturing outside the crop region.
-    EXPECT_EQ(.5f, mtx[0]);
+    EXPECT_EQ(.375f, mtx[0]);
     EXPECT_EQ(0.f, mtx[1]);
     EXPECT_EQ(0.f, mtx[2]);
     EXPECT_EQ(0.f, mtx[3]);
 
     EXPECT_EQ(0.f, mtx[4]);
-    EXPECT_EQ(-.5f, mtx[5]);
+    EXPECT_EQ(-.375f, mtx[5]);
     EXPECT_EQ(0.f, mtx[6]);
     EXPECT_EQ(0.f, mtx[7]);
 
@@ -595,7 +595,7 @@
     EXPECT_EQ(1.f, mtx[10]);
     EXPECT_EQ(0.f, mtx[11]);
 
-    EXPECT_EQ(0.f, mtx[12]);
+    EXPECT_EQ(.125f, mtx[12]);
     EXPECT_EQ(.5f, mtx[13]);
     EXPECT_EQ(0.f, mtx[14]);
     EXPECT_EQ(1.f, mtx[15]);
diff --git a/libs/utils/Tokenizer.cpp b/libs/utils/Tokenizer.cpp
index efda2bf..7067533 100644
--- a/libs/utils/Tokenizer.cpp
+++ b/libs/utils/Tokenizer.cpp
@@ -35,15 +35,18 @@
     return strchr(delimiters, ch) != NULL;
 }
 
-Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer, size_t length) :
+Tokenizer::Tokenizer(const String8& filename, FileMap* fileMap, char* buffer,
+        bool ownBuffer, size_t length) :
         mFilename(filename), mFileMap(fileMap),
-        mBuffer(buffer), mLength(length), mCurrent(buffer), mLineNumber(1) {
+        mBuffer(buffer), mOwnBuffer(ownBuffer), mLength(length),
+        mCurrent(buffer), mLineNumber(1) {
 }
 
 Tokenizer::~Tokenizer() {
     if (mFileMap) {
         mFileMap->release();
-    } else {
+    }
+    if (mOwnBuffer) {
         delete[] mBuffer;
     }
 }
@@ -65,6 +68,7 @@
             size_t length = size_t(stat.st_size);
 
             FileMap* fileMap = new FileMap();
+            bool ownBuffer = false;
             char* buffer;
             if (fileMap->create(NULL, fd, 0, length, true)) {
                 fileMap->advise(FileMap::SEQUENTIAL);
@@ -77,6 +81,7 @@
                 // The length we obtained from stat is wrong too (it will always be 4096)
                 // so we must trust that read will read the entire file.
                 buffer = new char[length];
+                ownBuffer = true;
                 ssize_t nrd = read(fd, buffer, length);
                 if (nrd < 0) {
                     result = -errno;
@@ -89,7 +94,7 @@
             }
 
             if (!result) {
-                *outTokenizer = new Tokenizer(filename, fileMap, buffer, length);
+                *outTokenizer = new Tokenizer(filename, fileMap, buffer, ownBuffer, length);
             }
         }
         close(fd);
@@ -97,6 +102,13 @@
     return result;
 }
 
+status_t Tokenizer::fromContents(const String8& filename,
+        const char* contents, Tokenizer** outTokenizer) {
+    *outTokenizer = new Tokenizer(filename, NULL,
+            const_cast<char*>(contents), false, strlen(contents));
+    return OK;
+}
+
 String8 Tokenizer::getLocation() const {
     String8 result;
     result.appendFormat("%s:%d", mFilename.string(), mLineNumber);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 93dd3a4..f220de3 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -87,7 +87,6 @@
         mHwWorkListDirty(false),
         mElectronBeamAnimationMode(0),
         mDebugRegion(0),
-        mDebugBackground(0),
         mDebugDDMS(0),
         mDebugDisableHWC(0),
         mDebugDisableTransformHint(0),
@@ -111,9 +110,6 @@
     property_get("debug.sf.showupdates", value, "0");
     mDebugRegion = atoi(value);
 
-    property_get("debug.sf.showbackground", value, "0");
-    mDebugBackground = atoi(value);
-
 #ifdef DDMS_DEBUGGING
     property_get("debug.sf.ddms", value, "0");
     mDebugDDMS = atoi(value);
@@ -123,7 +119,6 @@
 #endif
 
     ALOGI_IF(mDebugRegion,       "showupdates enabled");
-    ALOGI_IF(mDebugBackground,   "showbackground enabled");
     ALOGI_IF(mDebugDDMS,         "DDMS debugging enabled");
 }
 
@@ -902,9 +897,20 @@
     if (fbLayerCount) {
         // Never touch the framebuffer if we don't have any framebuffer layers
 
-        if (!mWormholeRegion.isEmpty()) {
-            // can happen with SurfaceView
-            drawWormhole();
+        if (hwc.getLayerCount(HWC_OVERLAY)) {
+            // when using overlays, we assume a fully transparent framebuffer
+            // NOTE: we could reduce how much we need to clear, for instance
+            // remove where there are opaque FB layers. however, on some
+            // GPUs doing a "clean slate" glClear might be more efficient.
+            // We'll revisit later if needed.
+            glClearColor(0, 0, 0, 0);
+            glClear(GL_COLOR_BUFFER_BIT);
+        } else {
+            // screen is already cleared here
+            if (!mWormholeRegion.isEmpty()) {
+                // can happen with SurfaceView
+                drawWormhole();
+            }
         }
 
         /*
@@ -919,9 +925,11 @@
             const sp<LayerBase>& layer(layers[i]);
             const Region clip(dirty.intersect(layer->visibleRegionScreen));
             if (!clip.isEmpty()) {
-                if (cur && (cur[i].compositionType != HWC_FRAMEBUFFER)) {
-                    if ((cur[i].hints & HWC_HINT_CLEAR_FB)
+                if (cur && (cur[i].compositionType == HWC_OVERLAY)) {
+                    if (i && (cur[i].hints & HWC_HINT_CLEAR_FB)
                             && layer->isOpaque()) {
+                        // never clear the very first layer since we're
+                        // guaranteed the FB is already cleared
                         layer->clearWithOpenGL(clip);
                     }
                     continue;
@@ -988,25 +996,9 @@
         return;
 
     glDisable(GL_TEXTURE_EXTERNAL_OES);
+    glDisable(GL_TEXTURE_2D);
     glDisable(GL_BLEND);
-
-    if (CC_LIKELY(!mDebugBackground)) {
-        glDisable(GL_TEXTURE_2D);
-        glColor4f(0,0,0,0);
-    } else {
-        const DisplayHardware& hw(graphicPlane(0).displayHardware());
-        const int32_t width = hw.getWidth();
-        const int32_t height = hw.getHeight();
-        const GLfloat tcoords[][2] = { { 0, 0 }, { 1, 0 },  { 1, 1 }, { 0, 1 } };
-        glTexCoordPointer(2, GL_FLOAT, 0, tcoords);
-        glEnableClientState(GL_TEXTURE_COORD_ARRAY);
-        glEnable(GL_TEXTURE_2D);
-        glBindTexture(GL_TEXTURE_2D, mWormholeTexName);
-        glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
-        glMatrixMode(GL_TEXTURE);
-        glLoadIdentity();
-        glScalef(width*(1.0f/32.0f), height*(1.0f/32.0f), 1);
-    }
+    glColor4f(0,0,0,0);
 
     GLfloat vertices[4][2];
     glVertexPointer(2, GL_FLOAT, 0, vertices);
@@ -1024,11 +1016,6 @@
         vertices[3][1] = r.bottom;
         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
     }
-
-    glDisableClientState(GL_TEXTURE_COORD_ARRAY);
-    glDisable(GL_TEXTURE_2D);
-    glLoadIdentity();
-    glMatrixMode(GL_MODELVIEW);
 }
 
 status_t SurfaceFlinger::addLayer(const sp<LayerBase>& layer)
@@ -1714,10 +1701,6 @@
                 invalidateHwcGeometry();
                 repaintEverything();
                 return NO_ERROR;
-            case 1003:  // SHOW_BACKGROUND
-                n = data.readInt32();
-                mDebugBackground = n ? 1 : 0;
-                return NO_ERROR;
             case 1004:{ // repaint everything
                 repaintEverything();
                 return NO_ERROR;
@@ -1746,7 +1729,7 @@
                 reply->writeInt32(0);
                 reply->writeInt32(0);
                 reply->writeInt32(mDebugRegion);
-                reply->writeInt32(mDebugBackground);
+                reply->writeInt32(0);
                 reply->writeInt32(mDebugDisableHWC);
                 return NO_ERROR;
             case 1013: {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 1aea452..d9c2033 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -350,7 +350,7 @@
 
             void        debugFlashRegions();
             void        drawWormhole() const;
-           
+
             void listLayersLocked(const Vector<String16>& args, size_t& index,
                     String8& result, char* buffer, size_t SIZE) const;
             void dumpStatsLocked(const Vector<String16>& args, size_t& index,
@@ -402,7 +402,6 @@
 
                 // don't use a lock for these, we don't care
                 int                         mDebugRegion;
-                int                         mDebugBackground;
                 int                         mDebugDDMS;
                 int                         mDebugDisableHWC;
                 int                         mDebugDisableTransformHint;