merge in jb-release history after reset to jb-dev
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 880f81f..165f11c 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -144,6 +144,7 @@
 
     dump_file("NETWORK DEV INFO", "/proc/net/dev");
     dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
+    dump_file("QTAGUID NETWORK INTERFACES INFO (xt)", "/proc/net/xt_qtaguid/iface_stat_fmt");
     dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
     dump_file("QTAGUID STATS INFO", "/proc/net/xt_qtaguid/stats");
 
@@ -176,8 +177,10 @@
     dump_file("ARP CACHE", "/proc/net/arp");
     run_command("IPTABLES", 10, SU_PATH, "root", "iptables", "-L", "-nvx", NULL);
     run_command("IP6TABLES", 10, SU_PATH, "root", "ip6tables", "-L", "-nvx", NULL);
-    run_command("IPTABLE NAT", 10, SU_PATH, "root", "iptables", "-t", "nat", "-L", "-n", NULL);
-    run_command("IPT6ABLE NAT", 10, SU_PATH, "root", "ip6tables", "-t", "nat", "-L", "-n", NULL);
+    run_command("IPTABLE NAT", 10, SU_PATH, "root", "iptables", "-t", "nat", "-L", "-nvx", NULL);
+    /* no ip6 nat */
+    run_command("IPTABLE RAW", 10, SU_PATH, "root", "iptables", "-t", "raw", "-L", "-nvx", NULL);
+    run_command("IP6TABLE RAW", 10, SU_PATH, "root", "ip6tables", "-t", "raw", "-L", "-nvx", NULL);
 
     run_command("WIFI NETWORKS", 20,
             SU_PATH, "root", "wpa_cli", "list_networks", NULL);
@@ -205,7 +208,7 @@
 
     run_command("FILESYSTEMS & FREE SPACE", 10, SU_PATH, "root", "df", NULL);
 
-    dump_file("PACKAGE SETTINGS", "/data/system/packages.xml");
+    run_command("PACKAGE SETTINGS", 20, SU_PATH, "root", "cat", "/data/system/packages.xml", NULL);
     dump_file("PACKAGE UID ERRORS", "/data/system/uiderrors.txt");
 
     run_command("LAST RADIO LOG", 10, "parse_radio_log", "/proc/last_radio_log", NULL);
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 9b6bc38..a0774cf 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -994,8 +994,6 @@
 }
 
 void BufferQueue::freeAllBuffersExceptHeadLocked() {
-    ALOGW_IF(!mQueue.isEmpty(),
-            "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
     int head = -1;
     if (!mQueue.empty()) {
         Fifo::iterator front(mQueue.begin());
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 1e58a21..30c0d9b 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -228,41 +228,46 @@
             mEGLSlots[buf].mGraphicBuffer = item.mGraphicBuffer;
         }
 
-        // Update the GL texture object.
+        // Update the GL texture object. We may have to do this even when
+        // item.mGraphicBuffer == NULL, if we destroyed the EGLImage when
+        // detaching from a context but the buffer has not been re-allocated.
         EGLImageKHR image = mEGLSlots[buf].mEglImage;
         if (image == EGL_NO_IMAGE_KHR) {
-            if (item.mGraphicBuffer == 0) {
+            if (mEGLSlots[buf].mGraphicBuffer == NULL) {
                 ST_LOGE("updateTexImage: buffer at slot %d is null", buf);
-                return BAD_VALUE;
-            }
-            image = createImage(dpy, item.mGraphicBuffer);
-            mEGLSlots[buf].mEglImage = image;
-            if (image == EGL_NO_IMAGE_KHR) {
-                // NOTE: if dpy was invalid, createImage() is guaranteed to
-                // fail. so we'd end up here.
-                return UNKNOWN_ERROR;
+                err = BAD_VALUE;
+            } else {
+                image = createImage(dpy, mEGLSlots[buf].mGraphicBuffer);
+                mEGLSlots[buf].mEglImage = image;
+                if (image == EGL_NO_IMAGE_KHR) {
+                    // NOTE: if dpy was invalid, createImage() is guaranteed to
+                    // fail. so we'd end up here.
+                    err = UNKNOWN_ERROR;
+                }
             }
         }
 
-        GLint error;
-        while ((error = glGetError()) != GL_NO_ERROR) {
-            ST_LOGW("updateTexImage: clearing GL error: %#04x", error);
+        if (err == NO_ERROR) {
+            GLint error;
+            while ((error = glGetError()) != GL_NO_ERROR) {
+                ST_LOGW("updateTexImage: clearing GL error: %#04x", error);
+            }
+
+            glBindTexture(mTexTarget, mTexName);
+            glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
+
+            while ((error = glGetError()) != GL_NO_ERROR) {
+                ST_LOGE("updateTexImage: error binding external texture image %p "
+                        "(slot %d): %#04x", image, buf, error);
+                err = UNKNOWN_ERROR;
+            }
+
+            if (err == NO_ERROR) {
+                err = syncForReleaseLocked(dpy);
+            }
         }
 
-        glBindTexture(mTexTarget, mTexName);
-        glEGLImageTargetTexture2DOES(mTexTarget, (GLeglImageOES)image);
-
-        while ((error = glGetError()) != GL_NO_ERROR) {
-            ST_LOGE("updateTexImage: error binding external texture image %p "
-                    "(slot %d): %#04x", image, buf, error);
-            err = UNKNOWN_ERROR;
-        }
-
-        if (err == OK) {
-            err = syncForReleaseLocked(dpy);
-        }
-
-        if (err != OK) {
+        if (err != NO_ERROR) {
             // Release the buffer we just acquired.  It's not safe to
             // release the old buffer, so instead we just drop the new frame.
             mBufferQueue->releaseBuffer(buf, dpy, mEGLSlots[buf].mFence);
@@ -277,12 +282,13 @@
 
         // release old buffer
         if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-            status_t status = mBufferQueue->releaseBuffer(mCurrentTexture, dpy, mEGLSlots[mCurrentTexture].mFence);
+            status_t status = mBufferQueue->releaseBuffer(mCurrentTexture, dpy,
+                    mEGLSlots[mCurrentTexture].mFence);
 
             mEGLSlots[mCurrentTexture].mFence = EGL_NO_SYNC_KHR;
             if (status == BufferQueue::STALE_BUFFER_SLOT) {
                 freeBufferLocked(mCurrentTexture);
-            } else if (status != OK) {
+            } else if (status != NO_ERROR) {
                 ST_LOGE("updateTexImage: released invalid buffer");
                 err = status;
             }
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index d708f6d..078c17b 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -2577,4 +2577,32 @@
     ASSERT_TRUE(checkPixel( 0,  0,  35,  35,  35,  35));
 }
 
+TEST_F(SurfaceTextureMultiContextGLTest,
+        UpdateTexImageSucceedsForBufferConsumedBeforeDetach) {
+    ASSERT_EQ(NO_ERROR, mST->setSynchronousMode(true));
+    ASSERT_EQ(NO_ERROR, mST->setBufferCountServer(2));
+
+    // produce two frames and consume them both on the primary context
+    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
+    mFW->waitForFrame();
+    ASSERT_EQ(OK, mST->updateTexImage());
+
+    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
+    mFW->waitForFrame();
+    ASSERT_EQ(OK, mST->updateTexImage());
+
+    // produce one more frame
+    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
+
+    // Detach from the primary context and attach to the secondary context
+    ASSERT_EQ(OK, mST->detachFromContext());
+    ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
+            mSecondEglContext));
+    ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID));
+
+    // Consume final frame on secondary context
+    mFW->waitForFrame();
+    ASSERT_EQ(OK, mST->updateTexImage());
+}
+
 } // namespace android
diff --git a/libs/utils/VectorImpl.cpp b/libs/utils/VectorImpl.cpp
index 220ae3e..e78faa8 100644
--- a/libs/utils/VectorImpl.cpp
+++ b/libs/utils/VectorImpl.cpp
@@ -382,8 +382,8 @@
             }
         }
     } else {
+        void* array = editArrayImpl();
         if (where != mCount) {
-            void* array = editArrayImpl();
             const void* from = reinterpret_cast<const uint8_t *>(array) + where*mItemSize;
             void* to = reinterpret_cast<uint8_t *>(array) + (where+amount)*mItemSize;
             _do_move_forward(to, from, mCount - where);
diff --git a/libs/utils/tests/Android.mk b/libs/utils/tests/Android.mk
index 98e4936..0a5b379 100644
--- a/libs/utils/tests/Android.mk
+++ b/libs/utils/tests/Android.mk
@@ -9,6 +9,7 @@
 	Looper_test.cpp \
 	String8_test.cpp \
 	Unicode_test.cpp \
+	Vector_test.cpp \
 	ZipFileRO_test.cpp
 
 shared_libraries := \
diff --git a/libs/utils/tests/Vector_test.cpp b/libs/utils/tests/Vector_test.cpp
new file mode 100644
index 0000000..d29c054
--- /dev/null
+++ b/libs/utils/tests/Vector_test.cpp
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2012 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.
+ */
+
+#define LOG_TAG "Vector_test"
+
+#include <utils/Vector.h>
+#include <cutils/log.h>
+#include <gtest/gtest.h>
+#include <unistd.h>
+
+namespace android {
+
+class VectorTest : public testing::Test {
+protected:
+    virtual void SetUp() {
+    }
+
+    virtual void TearDown() {
+    }
+
+public:
+};
+
+
+TEST_F(VectorTest, CopyOnWrite_CopyAndAddElements) {
+
+    Vector<int> vector;
+    Vector<int> other;
+    vector.setCapacity(8);
+
+    vector.add(1);
+    vector.add(2);
+    vector.add(3);
+
+    EXPECT_EQ(vector.size(), 3);
+
+    // copy the vector
+    other = vector;
+
+    EXPECT_EQ(other.size(), 3);
+
+    // add an element to the first vector
+    vector.add(4);
+
+    // make sure the sizes are correct
+    EXPECT_EQ(vector.size(), 4);
+    EXPECT_EQ(other.size(), 3);
+
+    // add an element to the copy
+    other.add(5);
+
+    // make sure the sizes are correct
+    EXPECT_EQ(vector.size(), 4);
+    EXPECT_EQ(other.size(), 4);
+
+    // make sure the content of both vectors are correct
+    EXPECT_EQ(vector[3], 4);
+    EXPECT_EQ(other[3], 5);
+}
+
+
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 35a7fd5..f4779e7 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -62,6 +62,7 @@
 
 #include <private/android_filesystem_config.h>
 #include <private/gui/SharedBufferStack.h>
+#include <gui/BitTube.h>
 
 #define EGL_VERSION_HW_ANDROID  0x3143
 
@@ -1845,6 +1846,35 @@
 
 // ---------------------------------------------------------------------------
 
+class VSyncWaiter {
+    DisplayEventReceiver::Event buffer[4];
+    sp<Looper> looper;
+    sp<IDisplayEventConnection> events;
+    sp<BitTube> eventTube;
+public:
+    VSyncWaiter(const sp<EventThread>& eventThread) {
+        looper = new Looper(true);
+        events = eventThread->createEventConnection();
+        eventTube = events->getDataChannel();
+        looper->addFd(eventTube->getFd(), 0, ALOOPER_EVENT_INPUT, 0, 0);
+        events->requestNextVsync();
+    }
+
+    void wait() {
+        ssize_t n;
+
+        looper->pollOnce(-1);
+        // we don't handle any errors here, it doesn't matter
+        // and we don't want to take the risk to get stuck.
+
+        // drain the events...
+        while ((n = DisplayEventReceiver::getEvents(
+                eventTube, buffer, 4)) > 0) ;
+
+        events->requestNextVsync();
+    }
+};
+
 status_t SurfaceFlinger::electronBeamOffAnimationImplLocked()
 {
     // get screen geometry
@@ -1937,6 +1967,8 @@
         }
     };
 
+    VSyncWaiter vsync(mEventThread);
+
     // the full animation is 24 frames
     char value[PROPERTY_VALUE_MAX];
     property_get("debug.sf.electron_frames", value, "24");
@@ -1963,6 +1995,9 @@
         const float vg = itg(i);
         const float vb = itb(i);
 
+        // wait for vsync
+        vsync.wait();
+
         // clear screen
         glColorMask(1,1,1,1);
         glClear(GL_COLOR_BUFFER_BIT);
@@ -1998,6 +2033,10 @@
     for (int i=0 ; i<nbFrames ; i++) {
         const float v = itg(i);
         hverts(vtx, v);
+
+        // wait for vsync
+        vsync.wait();
+
         glClear(GL_COLOR_BUFFER_BIT);
         glColor4f(1-v, 1-v, 1-v, 1);
         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -2095,6 +2134,8 @@
         }
     };
 
+    VSyncWaiter vsync(mEventThread);
+
     // the full animation is 12 frames
     int nbFrames = 8;
     s_curve_interpolator itr(nbFrames, 7.5f);
@@ -2108,6 +2149,10 @@
     for (int i=nbFrames-1 ; i>=0 ; i--) {
         const float v = itg(i);
         hverts(vtx, v);
+
+        // wait for vsync
+        vsync.wait();
+
         glClear(GL_COLOR_BUFFER_BIT);
         glColor4f(1-v, 1-v, 1-v, 1);
         glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
@@ -2124,6 +2169,9 @@
         const float vg = itg(i);
         const float vb = itb(i);
 
+        // wait for vsync
+        vsync.wait();
+
         // clear screen
         glColorMask(1,1,1,1);
         glClear(GL_COLOR_BUFFER_BIT);