Merge "View pressed state dispatching tweaks"
diff --git a/api/current.txt b/api/current.txt
index fffa1fe..137b672 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -16080,6 +16080,7 @@
   protected static abstract interface CalendarContract.RemindersColumns {
     field public static final java.lang.String EVENT_ID = "event_id";
     field public static final java.lang.String METHOD = "method";
+    field public static final int METHOD_ALARM = 4; // 0x4
     field public static final int METHOD_ALERT = 1; // 0x1
     field public static final int METHOD_DEFAULT = 0; // 0x0
     field public static final int METHOD_EMAIL = 2; // 0x2
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 16dc517..ebe28db 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -88,11 +88,11 @@
 
     if (screenshot_path[0]) {
         ALOGI("taking screenshot\n");
-        run_command(NULL, 5, "su", "root", "screenshot", screenshot_path, NULL);
+        run_command(NULL, 5, SU_PATH, "root", "screenshot", screenshot_path, NULL);
         ALOGI("wrote screenshot: %s\n", screenshot_path);
     }
 
-    run_command("SYSTEM SETTINGS", 20, "su", "root", "sqlite3",
+    run_command("SYSTEM SETTINGS", 20, SU_PATH, "root", "sqlite3",
             "/data/data/com.android.providers.settings/databases/settings.db",
             "pragma user_version; select * from system; select * from secure;", NULL);
     run_command("SYSTEM LOG", 20, "logcat", "-v", "threadtime", "-d", "*:v", NULL);
@@ -118,7 +118,7 @@
     run_command("EVENT LOG", 20, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL);
     run_command("RADIO LOG", 20, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL);
 
-    run_command("NETWORK INTERFACES", 10, "su", "root", "netcfg", NULL);
+    run_command("NETWORK INTERFACES", 10, SU_PATH, "root", "netcfg", NULL);
     dump_file("NETWORK DEV INFO", "/proc/net/dev");
     dump_file("QTAGUID NETWORK INTERFACES INFO", "/proc/net/xt_qtaguid/iface_stat_all");
     dump_file("QTAGUID CTRL INFO", "/proc/net/xt_qtaguid/ctrl");
@@ -133,28 +133,28 @@
     run_command("ROUTE TABLE 61", 10, "ip", "route", "show", "table", "61", NULL);
     run_command("ROUTE TABLE 61 v6", 10, "ip", "-6", "route", "show", "table", "61", NULL);
     dump_file("ARP CACHE", "/proc/net/arp");
-    run_command("IPTABLES", 10, "su", "root", "iptables", "-L", "-nvx", NULL);
-    run_command("IP6TABLES", 10, "su", "root", "ip6tables", "-L", "-nvx", NULL);
-    run_command("IPTABLE NAT", 10, "su", "root", "iptables", "-t", "nat", "-L", "-n", NULL);
-    run_command("IPT6ABLE NAT", 10, "su", "root", "ip6tables", "-t", "nat", "-L", "-n", NULL);
+    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("WIFI NETWORKS", 20,
-            "su", "root", "wpa_cli", "list_networks", NULL);
+            SU_PATH, "root", "wpa_cli", "list_networks", NULL);
 
     property_get("dhcp.wlan0.gateway", network, "");
     if (network[0])
-        run_command("PING GATEWAY", 10, "su", "root", "ping", "-c", "3", "-i", ".5", network, NULL);
+        run_command("PING GATEWAY", 10, SU_PATH, "root", "ping", "-c", "3", "-i", ".5", network, NULL);
     property_get("dhcp.wlan0.dns1", network, "");
     if (network[0])
-        run_command("PING DNS1", 10, "su", "root", "ping", "-c", "3", "-i", ".5", network, NULL);
+        run_command("PING DNS1", 10, SU_PATH, "root", "ping", "-c", "3", "-i", ".5", network, NULL);
     property_get("dhcp.wlan0.dns2", network, "");
     if (network[0])
-        run_command("PING DNS2", 10, "su", "root", "ping", "-c", "3", "-i", ".5", network, NULL);
+        run_command("PING DNS2", 10, SU_PATH, "root", "ping", "-c", "3", "-i", ".5", network, NULL);
 #ifdef FWDUMP_bcm4329
     run_command("DUMP WIFI STATUS", 20,
-            "su", "root", "dhdutil", "-i", "wlan0", "dump", NULL);
+            SU_PATH, "root", "dhdutil", "-i", "wlan0", "dump", NULL);
     run_command("DUMP WIFI INTERNAL COUNTERS", 20,
-            "su", "root", "wlutil", "counters", NULL);
+            SU_PATH, "root", "wlutil", "counters", NULL);
 #endif
 
     char ril_dumpstate_timeout[PROPERTY_VALUE_MAX] = {0};
@@ -168,7 +168,7 @@
                     "vril-dump", NULL);
         } else {
             run_command("DUMP VENDOR RIL LOGS", atoi(ril_dumpstate_timeout),
-                    "su", "root", "vril-dump", NULL);
+                    SU_PATH, "root", "vril-dump", NULL);
         }
     }
 
@@ -192,7 +192,7 @@
     dump_file("BINDER STATS", "/sys/kernel/debug/binder/stats");
     dump_file("BINDER STATE", "/sys/kernel/debug/binder/state");
 
-    run_command("FILESYSTEMS & FREE SPACE", 10, "su", "root", "df", NULL);
+    run_command("FILESYSTEMS & FREE SPACE", 10, SU_PATH, "root", "df", NULL);
 
     dump_file("PACKAGE SETTINGS", "/data/system/packages.xml");
     dump_file("PACKAGE UID ERRORS", "/data/system/uiderrors.txt");
@@ -218,7 +218,7 @@
     dump_file(NULL, "/sys/class/leds/lcd-backlight/registers");
     printf("\n");
 
-    run_command("LIST OF OPEN FILES", 10, "su", "root", "lsof", NULL);
+    run_command("LIST OF OPEN FILES", 10, SU_PATH, "root", "lsof", NULL);
 
     for_each_pid(do_showmap, "SMAPS OF ALL PROCESSES");
 
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index b02db0b..c1c2ad8 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -21,6 +21,8 @@
 #include <unistd.h>
 #include <stdio.h>
 
+#define SU_PATH "/system/xbin/su"
+
 /* prints the contents of a file */
 int dump_file(const char *title, const char* path);
 
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index 21526f9..0d5ab90 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -127,7 +127,7 @@
 
     sprintf(title, "SHOW MAP %d (%s)", pid, name);
     sprintf(arg, "%d", pid);
-    run_command(title, 10, "su", "root", "showmap", arg, NULL);
+    run_command(title, 10, SU_PATH, "root", "showmap", arg, NULL);
 }
 
 /* prints the contents of a file */
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index f427e78..492fcc7 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -149,7 +149,7 @@
  * {@link Fragment#getFragmentManager() Fragment.getFragmentManager()}.
  *
  * <p>The Fragment class can be used many ways to achieve a wide variety of
- * results.  It is core, it represents a particular operation or interface
+ * results. In its core, it represents a particular operation or interface
  * that is running within a larger {@link Activity}.  A Fragment is closely
  * tied to the Activity it is in, and can not be used apart from one.  Though
  * Fragment defines its own lifecycle, that lifecycle is dependent on its
diff --git a/core/java/android/provider/CalendarContract.java b/core/java/android/provider/CalendarContract.java
index 413150b..fa59b32f 100644
--- a/core/java/android/provider/CalendarContract.java
+++ b/core/java/android/provider/CalendarContract.java
@@ -402,8 +402,8 @@
          * A comma separated list of reminder methods supported for this
          * calendar in the format "#,#,#". Valid types are
          * {@link Reminders#METHOD_DEFAULT}, {@link Reminders#METHOD_ALERT},
-         * {@link Reminders#METHOD_EMAIL}, {@link Reminders#METHOD_SMS}. Column
-         * name.
+         * {@link Reminders#METHOD_EMAIL}, {@link Reminders#METHOD_SMS},
+         * {@link Reminders#METHOD_ALARM}. Column name.
          * <P>Type: TEXT</P>
          */
         public static final String ALLOWED_REMINDERS = "allowedReminders";
@@ -1930,11 +1930,11 @@
 
         /**
          * The alarm method, as set on the server. {@link #METHOD_DEFAULT},
-         * {@link #METHOD_ALERT}, {@link #METHOD_EMAIL}, and {@link #METHOD_SMS}
-         * are possible values; the device will only process
-         * {@link #METHOD_DEFAULT} and {@link #METHOD_ALERT} reminders (the
-         * other types are simply stored so we can send the same reminder info
-         * back to the server when we make changes).
+         * {@link #METHOD_ALERT}, {@link #METHOD_EMAIL}, {@link #METHOD_SMS} and
+         * {@link #METHOD_ALARM} are possible values; the device will only
+         * process {@link #METHOD_DEFAULT} and {@link #METHOD_ALERT} reminders
+         * (the other types are simply stored so we can send the same reminder
+         * info back to the server when we make changes).
          */
         public static final String METHOD = "method";
 
@@ -1942,6 +1942,7 @@
         public static final int METHOD_ALERT = 1;
         public static final int METHOD_EMAIL = 2;
         public static final int METHOD_SMS = 3;
+        public static final int METHOD_ALARM = 4;
     }
 
     /**
diff --git a/include/gui/BufferQueue.h b/include/gui/BufferQueue.h
index dd1558c..8c21a28 100644
--- a/include/gui/BufferQueue.h
+++ b/include/gui/BufferQueue.h
@@ -40,6 +40,7 @@
     };
     enum { NUM_BUFFER_SLOTS = 32 };
     enum { NO_CONNECTED_API = 0 };
+    enum { INVALID_BUFFER_SLOT = -1 };
 
     struct FrameAvailableListener : public virtual RefBase {
         // onFrameAvailable() is called from queueBuffer() each time an
@@ -119,8 +120,91 @@
     // connected to the specified client API.
     virtual status_t disconnect(int api);
 
-protected:
+    // dump our state in a String
+    virtual void dump(String8& result) const;
+    virtual void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
 
+    // public facing structure for BufferSlot
+    struct BufferItem {
+
+        BufferItem()
+         :
+           mTransform(0),
+           mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+           mTimestamp(0),
+           mFrameNumber(0),
+           mBuf(INVALID_BUFFER_SLOT) {
+             mCrop.makeInvalid();
+         }
+        // mGraphicBuffer points to the buffer allocated for this slot or is NULL
+        // if no buffer has been allocated.
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // mCrop is the current crop rectangle for this buffer slot. This gets
+        // set to mNextCrop each time queueBuffer gets called for this buffer.
+        Rect mCrop;
+
+        // mTransform is the current transform flags for this buffer slot. This
+        // gets set to mNextTransform each time queueBuffer gets called for this
+        // slot.
+        uint32_t mTransform;
+
+        // mScalingMode is the current scaling mode for this buffer slot. This
+        // gets set to mNextScalingMode each time queueBuffer gets called for
+        // this slot.
+        uint32_t mScalingMode;
+
+        // mTimestamp is the current timestamp for this buffer slot. This gets
+        // to set by queueBuffer each time this slot is queued.
+        int64_t mTimestamp;
+
+        // mFrameNumber is the number of the queued frame for this slot.
+        uint64_t mFrameNumber;
+
+        // buf is the slot index of this buffer
+        int mBuf;
+
+    };
+
+    // The following public functions is the consumer facing interface
+
+    // acquire consumes a buffer by transferring its ownership to a consumer.
+    // buffer contains the GraphicBuffer and its corresponding information.
+    // buffer.mGraphicsBuffer will be NULL when the buffer has been already
+    // acquired by the consumer.
+
+    status_t acquire(BufferItem *buffer);
+
+    // releaseBuffer releases a buffer slot from the consumer back to the
+    // BufferQueue pending a fence sync.
+    status_t releaseBuffer(int buf, EGLDisplay display, EGLSyncKHR fence);
+
+    // consumerDisconnect disconnects a consumer from the BufferQueue. All
+    // buffers will be freed.
+    status_t consumerDisconnect();
+
+    // setDefaultBufferSize is used to set the size of buffers returned by
+    // requestBuffers when a with and height of zero is requested.
+    status_t setDefaultBufferSize(uint32_t w, uint32_t h);
+
+    // setBufferCountServer set the buffer count. If the client has requested
+    // a buffer count using setBufferCount, the server-buffer count will
+    // take effect once the client sets the count back to zero.
+    status_t setBufferCountServer(int bufferCount);
+
+    // isSynchronousMode returns whether the SurfaceTexture is currently in
+    // synchronous mode.
+    bool isSynchronousMode() const;
+
+    // setConsumerName sets the name used in logging
+    void setConsumerName(const String8& name);
+
+    // setFrameAvailableListener sets the listener object that will be notified
+    // when a new frame becomes available.
+    void setFrameAvailableListener(const sp<FrameAvailableListener>& listener);
+
+
+private:
     // freeBufferLocked frees the resources (both GraphicBuffer and EGLImage)
     // for the given slot.
     void freeBufferLocked(int index);
@@ -145,20 +229,18 @@
 
     status_t setBufferCountServerLocked(int bufferCount);
 
-    enum { INVALID_BUFFER_SLOT = -1 };
-
     struct BufferSlot {
 
         BufferSlot()
-        : mEglImage(EGL_NO_IMAGE_KHR),
-          mEglDisplay(EGL_NO_DISPLAY),
+        : mEglDisplay(EGL_NO_DISPLAY),
           mBufferState(BufferSlot::FREE),
           mRequestBufferCalled(false),
           mTransform(0),
           mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
           mTimestamp(0),
           mFrameNumber(0),
-          mFence(EGL_NO_SYNC_KHR) {
+          mFence(EGL_NO_SYNC_KHR),
+          mAcquireCalled(false) {
             mCrop.makeInvalid();
         }
 
@@ -166,9 +248,6 @@
         // if no buffer has been allocated.
         sp<GraphicBuffer> mGraphicBuffer;
 
-        // mEglImage is the EGLImage created from mGraphicBuffer.
-        EGLImageKHR mEglImage;
-
         // mEglDisplay is the EGLDisplay used to create mEglImage.
         EGLDisplay mEglDisplay;
 
@@ -178,6 +257,7 @@
             // FREE indicates that the buffer is not currently being used and
             // will not be used in the future until it gets dequeued and
             // subsequently queued by the client.
+            // aka "owned by BufferQueue, ready to be dequeued"
             FREE = 0,
 
             // DEQUEUED indicates that the buffer has been dequeued by the
@@ -190,6 +270,7 @@
             // dequeued by the client.  That means that the current buffer can
             // be in either the DEQUEUED or QUEUED state.  In asynchronous mode,
             // however, the current buffer is always in the QUEUED state.
+            // aka "owned by producer, ready to be queued"
             DEQUEUED = 1,
 
             // QUEUED indicates that the buffer has been queued by the client,
@@ -199,7 +280,11 @@
             // the current buffer may be dequeued by the client under some
             // circumstances. See the note about the current buffer in the
             // documentation for DEQUEUED.
+            // aka "owned by BufferQueue, ready to be acquired"
             QUEUED = 2,
+
+            // aka "owned by consumer, ready to be released"
+            ACQUIRED = 3
         };
 
         // mBufferState is the current state of this buffer slot.
@@ -236,6 +321,9 @@
         // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
         // on a compile-time option) set to a new sync object in updateTexImage.
         EGLSyncKHR mFence;
+
+        // Indicates whether this buffer has been seen by a consumer yet
+        bool mAcquireCalled;
     };
 
     // mSlots is the array of buffer slots that must be mirrored on the client
@@ -245,7 +333,6 @@
     // for a slot when requestBuffer is called with that slot's index.
     BufferSlot mSlots[NUM_BUFFER_SLOTS];
 
-
     // mDefaultWidth holds the default width of allocated buffers. It is used
     // in requestBuffers() if a width and height of zero is specified.
     uint32_t mDefaultWidth;
@@ -271,14 +358,6 @@
     // mServerBufferCount buffer count requested by the server-side
     int mServerBufferCount;
 
-    // mCurrentTexture is the buffer slot index of the buffer that is currently
-    // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
-    // indicating that no buffer slot is currently bound to the texture. Note,
-    // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
-    // that no buffer is bound to the texture. A call to setBufferCount will
-    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
-    int mCurrentTexture;
-
     // mNextCrop is the crop rectangle that will be used for the next buffer
     // that gets queued. It is set by calling setCrop.
     Rect mNextCrop;
@@ -327,7 +406,7 @@
 
     // mName is a string used to identify the BufferQueue in log messages.
     // It is set by the setName method.
-    String8 mName;
+    String8 mConsumerName;
 
     // mMutex is the mutex used to prevent concurrent access to the member
     // variables of BufferQueue objects. It must be locked whenever the
@@ -337,6 +416,8 @@
     // mFrameCounter is the free running counter, incremented for every buffer queued
     // with the surface Texture.
     uint64_t mFrameCounter;
+
+    bool mBufferHasBeenQueued;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/SurfaceTexture.h b/include/gui/SurfaceTexture.h
index dcab049..5531e53 100644
--- a/include/gui/SurfaceTexture.h
+++ b/include/gui/SurfaceTexture.h
@@ -153,8 +153,8 @@
     void setName(const String8& name);
 
     // dump our state in a String
-    void dump(String8& result) const;
-    void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
+    virtual void dump(String8& result) const;
+    virtual void dump(String8& result, const char* prefix, char* buffer, size_t SIZE) const;
 
 protected:
 
@@ -217,6 +217,56 @@
     // browser's tile cache exceeds.
     const GLenum mTexTarget;
 
+    // SurfaceTexture maintains EGL information about GraphicBuffers that corresponds
+    // directly with BufferQueue's buffers
+    struct EGLSlot {
+        EGLSlot()
+        : mEglImage(EGL_NO_IMAGE_KHR),
+          mEglDisplay(EGL_NO_DISPLAY),
+          mFence(EGL_NO_SYNC_KHR) {
+        }
+
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // mEglImage is the EGLImage created from mGraphicBuffer.
+        EGLImageKHR mEglImage;
+
+        // mEglDisplay is the EGLDisplay used to create mEglImage.
+        EGLDisplay mEglDisplay;
+
+        // mFence is the EGL sync object that must signal before the buffer
+        // associated with this buffer slot may be dequeued. It is initialized
+        // to EGL_NO_SYNC_KHR when the buffer is created and (optionally, based
+        // on a compile-time option) set to a new sync object in updateTexImage.
+        EGLSyncKHR mFence;
+    };
+
+    EGLSlot mEGLSlots[NUM_BUFFER_SLOTS];
+
+    // mAbandoned indicates that the BufferQueue will no longer be used to
+    // consume images buffers pushed to it using the ISurfaceTexture interface.
+    // It is initialized to false, and set to true in the abandon method.  A
+    // BufferQueue that has been abandoned will return the NO_INIT error from
+    // all ISurfaceTexture methods capable of returning an error.
+    bool mAbandoned;
+
+    // mName is a string used to identify the SurfaceTexture in log messages.
+    // It can be set by the setName method.
+    String8 mName;
+
+    // mMutex is the mutex used to prevent concurrent access to the member
+    // variables of SurfaceTexture objects. It must be locked whenever the
+    // member variables are accessed.
+    mutable Mutex mMutex;
+
+    // mCurrentTexture is the buffer slot index of the buffer that is currently
+    // bound to the OpenGL texture. It is initialized to INVALID_BUFFER_SLOT,
+    // indicating that no buffer slot is currently bound to the texture. Note,
+    // however, that a value of INVALID_BUFFER_SLOT does not necessarily mean
+    // that no buffer is bound to the texture. A call to setBufferCount will
+    // reset mCurrentTexture to INVALID_BUFFER_SLOT.
+    int mCurrentTexture;
+
 };
 
 // ----------------------------------------------------------------------------
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index 261336a..66fc16d 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -15,6 +15,7 @@
  */
 
 #define LOG_TAG "BufferQueue"
+//#define LOG_NDEBUG 0
 
 #define GL_GLEXT_PROTOTYPES
 #define EGL_EGLEXT_PROTOTYPES
@@ -27,6 +28,7 @@
 #include <private/gui/ComposerService.h>
 
 #include <utils/Log.h>
+#include <gui/SurfaceTexture.h>
 
 // This compile option causes SurfaceTexture to return the buffer that is currently
 // attached to the GL texture from dequeueBuffer when no other buffers are
@@ -34,6 +36,10 @@
 // implicit cross-process synchronization to prevent the buffer from being
 // written to before the buffer has (a) been detached from the GL texture and
 // (b) all GL reads from the buffer have completed.
+
+// During refactoring, do not support dequeuing the current buffer
+#undef ALLOW_DEQUEUE_CURRENT_BUFFER
+
 #ifdef ALLOW_DEQUEUE_CURRENT_BUFFER
 #define FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER    true
 #warning "ALLOW_DEQUEUE_CURRENT_BUFFER enabled"
@@ -42,11 +48,11 @@
 #endif
 
 // Macros for including the BufferQueue name in log messages
-#define ST_LOGV(x, ...) ALOGV("[%s] "x, mName.string(), ##__VA_ARGS__)
-#define ST_LOGD(x, ...) ALOGD("[%s] "x, mName.string(), ##__VA_ARGS__)
-#define ST_LOGI(x, ...) ALOGI("[%s] "x, mName.string(), ##__VA_ARGS__)
-#define ST_LOGW(x, ...) ALOGW("[%s] "x, mName.string(), ##__VA_ARGS__)
-#define ST_LOGE(x, ...) ALOGE("[%s] "x, mName.string(), ##__VA_ARGS__)
+#define ST_LOGV(x, ...) ALOGV("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define ST_LOGD(x, ...) ALOGD("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define ST_LOGI(x, ...) ALOGI("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define ST_LOGW(x, ...) ALOGW("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
+#define ST_LOGE(x, ...) ALOGE("[%s] "x, mConsumerName.string(), ##__VA_ARGS__)
 
 namespace android {
 
@@ -63,17 +69,17 @@
     mBufferCount(MIN_ASYNC_BUFFER_SLOTS),
     mClientBufferCount(0),
     mServerBufferCount(MIN_ASYNC_BUFFER_SLOTS),
-    mCurrentTexture(INVALID_BUFFER_SLOT),
     mNextTransform(0),
     mNextScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
     mSynchronousMode(false),
     mAllowSynchronousMode(allowSynchronousMode),
     mConnectedApi(NO_CONNECTED_API),
     mAbandoned(false),
-    mFrameCounter(0)
+    mFrameCounter(0),
+    mBufferHasBeenQueued(false)
 {
     // Choose a name using the PID and a process-unique ID.
-    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+    mConsumerName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
 
     ST_LOGV("BufferQueue");
     sp<ISurfaceComposer> composer(ComposerService::getComposerService());
@@ -119,6 +125,23 @@
     return OK;
 }
 
+bool BufferQueue::isSynchronousMode() const {
+    Mutex::Autolock lock(mMutex);
+    return mSynchronousMode;
+}
+
+void BufferQueue::setConsumerName(const String8& name) {
+    Mutex::Autolock lock(mMutex);
+    mConsumerName = name;
+}
+
+void BufferQueue::setFrameAvailableListener(
+        const sp<FrameAvailableListener>& listener) {
+    ST_LOGV("setFrameAvailableListener");
+    Mutex::Autolock lock(mMutex);
+    mFrameAvailableListener = listener;
+}
+
 status_t BufferQueue::setBufferCount(int bufferCount) {
     ST_LOGV("setBufferCount: count=%d", bufferCount);
     Mutex::Autolock lock(mMutex);
@@ -160,7 +183,7 @@
     freeAllBuffersLocked();
     mBufferCount = bufferCount;
     mClientBufferCount = bufferCount;
-    mCurrentTexture = INVALID_BUFFER_SLOT;
+    mBufferHasBeenQueued = false;
     mQueue.clear();
     mDequeueCondition.signal();
     return OK;
@@ -276,7 +299,7 @@
                 mBufferCount = mServerBufferCount;
                 if (mBufferCount < minBufferCountNeeded)
                     mBufferCount = minBufferCountNeeded;
-                mCurrentTexture = INVALID_BUFFER_SLOT;
+                mBufferHasBeenQueued = false;
                 returnFlags |= ISurfaceTexture::RELEASE_ALL_BUFFERS;
             }
 
@@ -290,19 +313,12 @@
                     dequeuedCount++;
                 }
 
-                // if buffer is FREE it CANNOT be current
-                ALOGW_IF((state == BufferSlot::FREE) && (mCurrentTexture==i),
-                        "dequeueBuffer: buffer %d is both FREE and current!",
-                        i);
-
-                if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER) {
-                    if (state == BufferSlot::FREE || i == mCurrentTexture) {
-                        foundSync = i;
-                        if (i != mCurrentTexture) {
-                            found = i;
-                            break;
-                        }
-                    }
+                // this logic used to be if (FLAG_ALLOW_DEQUEUE_CURRENT_BUFFER)
+                // but dequeuing the current buffer is disabled.
+                if (false) {
+                    // This functionality has been temporarily removed so
+                    // BufferQueue and SurfaceTexture can be refactored into
+                    // separate objects
                 } else {
                     if (state == BufferSlot::FREE) {
                         /* We return the oldest of the free buffers to avoid
@@ -331,8 +347,7 @@
             // See whether a buffer has been queued since the last
             // setBufferCount so we know whether to perform the
             // MIN_UNDEQUEUED_BUFFERS check below.
-            bool bufferHasBeenQueued = mCurrentTexture != INVALID_BUFFER_SLOT;
-            if (bufferHasBeenQueued) {
+            if (mBufferHasBeenQueued) {
                 // make sure the client is not trying to dequeue more buffers
                 // than allowed.
                 const int avail = mBufferCount - (dequeuedCount+1);
@@ -404,27 +419,23 @@
             if (updateFormat) {
                 mPixelFormat = format;
             }
+
+            mSlots[buf].mAcquireCalled = false;
             mSlots[buf].mGraphicBuffer = graphicBuffer;
             mSlots[buf].mRequestBufferCalled = false;
             mSlots[buf].mFence = EGL_NO_SYNC_KHR;
-            if (mSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
-                eglDestroyImageKHR(mSlots[buf].mEglDisplay,
-                        mSlots[buf].mEglImage);
-                mSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
-                mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
-            }
-            if (mCurrentTexture == buf) {
-                // The current texture no longer references the buffer in this slot
-                // since we just allocated a new buffer.
-                mCurrentTexture = INVALID_BUFFER_SLOT;
-            }
+            mSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
+
+
+
+
             returnFlags |= ISurfaceTexture::BUFFER_NEEDS_REALLOCATION;
         }
 
         dpy = mSlots[buf].mEglDisplay;
         fence = mSlots[buf].mFence;
         mSlots[buf].mFence = EGL_NO_SYNC_KHR;
-    }
+    }  // end lock scope
 
     if (fence != EGL_NO_SYNC_KHR) {
         EGLint result = eglClientWaitSyncKHR(dpy, fence, 0, 1000000000);
@@ -437,6 +448,7 @@
             ALOGE("dequeueBuffer: timeout waiting for fence");
         }
         eglDestroySyncKHR(dpy, fence);
+
     }
 
     ST_LOGV("dequeueBuffer: returning slot=%d buf=%p flags=%#x", *outBuf,
@@ -496,9 +508,6 @@
             ST_LOGE("queueBuffer: slot %d is not owned by the client "
                     "(state=%d)", buf, mSlots[buf].mBufferState);
             return -EINVAL;
-        } else if (buf == mCurrentTexture) {
-            ST_LOGE("queueBuffer: slot %d is current!", buf);
-            return -EINVAL;
         } else if (!mSlots[buf].mRequestBufferCalled) {
             ST_LOGE("queueBuffer: slot %d was enqueued without requesting a "
                     "buffer", buf);
@@ -538,6 +547,7 @@
         mFrameCounter++;
         mSlots[buf].mFrameNumber = mFrameCounter;
 
+        mBufferHasBeenQueued = true;
         mDequeueCondition.signal();
 
         *outWidth = mDefaultWidth;
@@ -647,6 +657,9 @@
             err = -EINVAL;
             break;
     }
+
+    mBufferHasBeenQueued = false;
+
     return err;
 }
 
@@ -687,26 +700,185 @@
     return err;
 }
 
+void BufferQueue::dump(String8& result) const
+{
+    char buffer[1024];
+    BufferQueue::dump(result, "", buffer, 1024);
+}
+
+void BufferQueue::dump(String8& result, const char* prefix,
+        char* buffer, size_t SIZE) const
+{
+    Mutex::Autolock _l(mMutex);
+    snprintf(buffer, SIZE,
+            "%snext   : {crop=[%d,%d,%d,%d], transform=0x%02x}\n"
+            ,prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right,
+            mNextCrop.bottom, mNextTransform
+    );
+    result.append(buffer);
+
+    String8 fifo;
+    int fifoSize = 0;
+    Fifo::const_iterator i(mQueue.begin());
+    while (i != mQueue.end()) {
+       snprintf(buffer, SIZE, "%02d ", *i++);
+       fifoSize++;
+       fifo.append(buffer);
+    }
+
+    snprintf(buffer, SIZE,
+            "%s-BufferQueue mBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
+            "mPixelFormat=%d, FIFO(%d)={%s}\n",
+            prefix, mBufferCount, mSynchronousMode, mDefaultWidth,
+            mDefaultHeight, mPixelFormat, fifoSize, fifo.string());
+    result.append(buffer);
+
+
+    struct {
+        const char * operator()(int state) const {
+            switch (state) {
+                case BufferSlot::DEQUEUED: return "DEQUEUED";
+                case BufferSlot::QUEUED: return "QUEUED";
+                case BufferSlot::FREE: return "FREE";
+                case BufferSlot::ACQUIRED: return "ACQUIRED";
+                default: return "Unknown";
+            }
+        }
+    } stateName;
+
+    for (int i=0 ; i<mBufferCount ; i++) {
+        const BufferSlot& slot(mSlots[i]);
+        snprintf(buffer, SIZE,
+                "%s%s[%02d] "
+                "state=%-8s, crop=[%d,%d,%d,%d], "
+                "transform=0x%02x, timestamp=%lld",
+                prefix, (slot.mBufferState == BufferSlot::ACQUIRED)?">":" ", i,
+                stateName(slot.mBufferState),
+                slot.mCrop.left, slot.mCrop.top, slot.mCrop.right,
+                slot.mCrop.bottom, slot.mTransform, slot.mTimestamp
+        );
+        result.append(buffer);
+
+        const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
+        if (buf != NULL) {
+            snprintf(buffer, SIZE,
+                    ", %p [%4ux%4u:%4u,%3X]",
+                    buf->handle, buf->width, buf->height, buf->stride,
+                    buf->format);
+            result.append(buffer);
+        }
+        result.append("\n");
+    }
+}
+
 void BufferQueue::freeBufferLocked(int i) {
     mSlots[i].mGraphicBuffer = 0;
     mSlots[i].mBufferState = BufferSlot::FREE;
     mSlots[i].mFrameNumber = 0;
-    if (mSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
-        eglDestroyImageKHR(mSlots[i].mEglDisplay, mSlots[i].mEglImage);
-        mSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
-        mSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+    mSlots[i].mAcquireCalled = false;
+
+    // destroy fence as BufferQueue now takes ownership
+    if (mSlots[i].mFence != EGL_NO_SYNC_KHR) {
+        eglDestroySyncKHR(mSlots[i].mEglDisplay, mSlots[i].mFence);
+        mSlots[i].mFence = EGL_NO_SYNC_KHR;
     }
 }
 
 void BufferQueue::freeAllBuffersLocked() {
     ALOGW_IF(!mQueue.isEmpty(),
             "freeAllBuffersLocked called but mQueue is not empty");
-    mCurrentTexture = INVALID_BUFFER_SLOT;
+    mQueue.clear();
+    mBufferHasBeenQueued = false;
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
         freeBufferLocked(i);
     }
 }
 
+status_t BufferQueue::acquire(BufferItem *buffer) {
+    Mutex::Autolock _l(mMutex);
+    // check if queue is empty
+    // In asynchronous mode the list is guaranteed to be one buffer
+    // deep, while in synchronous mode we use the oldest buffer.
+    if (!mQueue.empty()) {
+        Fifo::iterator front(mQueue.begin());
+        int buf = *front;
+
+        if (mSlots[buf].mAcquireCalled) {
+            buffer->mGraphicBuffer = NULL;
+        }
+        else {
+            buffer->mGraphicBuffer = mSlots[buf].mGraphicBuffer;
+        }
+        buffer->mCrop = mSlots[buf].mCrop;
+        buffer->mTransform = mSlots[buf].mTransform;
+        buffer->mScalingMode = mSlots[buf].mScalingMode;
+        buffer->mFrameNumber = mSlots[buf].mFrameNumber;
+        buffer->mBuf = buf;
+        mSlots[buf].mAcquireCalled = true;
+
+        mSlots[buf].mBufferState = BufferSlot::ACQUIRED;
+        mQueue.erase(front);
+    }
+    else {
+        return -EINVAL; //should be a better return code
+    }
+
+    return OK;
+}
+
+status_t BufferQueue::releaseBuffer(int buf, EGLDisplay display,
+        EGLSyncKHR fence) {
+    Mutex::Autolock _l(mMutex);
+
+    if (buf == INVALID_BUFFER_SLOT) {
+        return -EINVAL;
+    }
+
+    mSlots[buf].mEglDisplay = display;
+    mSlots[buf].mFence = fence;
+
+    // The current buffer becomes FREE if it was still in the queued
+    // state. If it has already been given to the client
+    // (synchronous mode), then it stays in DEQUEUED state.
+    if (mSlots[buf].mBufferState == BufferSlot::QUEUED
+            || mSlots[buf].mBufferState == BufferSlot::ACQUIRED) {
+        mSlots[buf].mBufferState = BufferSlot::FREE;
+    }
+    mDequeueCondition.signal();
+
+    return OK;
+}
+
+status_t BufferQueue::consumerDisconnect() {
+    Mutex::Autolock lock(mMutex);
+    // Once the SurfaceTexture disconnects, the BufferQueue
+    // is considered abandoned
+    mAbandoned = true;
+    freeAllBuffersLocked();
+    mDequeueCondition.signal();
+    return OK;
+}
+
+status_t BufferQueue::setDefaultBufferSize(uint32_t w, uint32_t h)
+{
+    ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
+    if (!w || !h) {
+        ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
+                w, h);
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock lock(mMutex);
+    mDefaultWidth = w;
+    mDefaultHeight = h;
+    return OK;
+}
+
+status_t BufferQueue::setBufferCountServer(int bufferCount) {
+    Mutex::Autolock lock(mMutex);
+    return setBufferCountServerLocked(bufferCount);
+}
+
 void BufferQueue::freeAllBuffersExceptHeadLocked() {
     ALOGW_IF(!mQueue.isEmpty(),
             "freeAllBuffersExceptCurrentLocked called but mQueue is not empty");
@@ -715,7 +887,7 @@
         Fifo::iterator front(mQueue.begin());
         head = *front;
     }
-    mCurrentTexture = INVALID_BUFFER_SLOT;
+    mBufferHasBeenQueued = false;
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
         if (i != head) {
             freeBufferLocked(i);
diff --git a/libs/gui/SurfaceTexture.cpp b/libs/gui/SurfaceTexture.cpp
index 5f0013c..a23a328 100644
--- a/libs/gui/SurfaceTexture.cpp
+++ b/libs/gui/SurfaceTexture.cpp
@@ -96,6 +96,11 @@
 
 static void mtxMul(float out[16], const float a[16], const float b[16]);
 
+// Get an ID that's unique within this process.
+static int32_t createProcessUniqueId() {
+    static volatile int32_t globalCounter = 0;
+    return android_atomic_inc(&globalCounter);
+}
 
 SurfaceTexture::SurfaceTexture(GLuint tex, bool allowSynchronousMode,
         GLenum texTarget, bool useFenceSync) :
@@ -108,8 +113,13 @@
 #else
     mUseFenceSync(false),
 #endif
-    mTexTarget(texTarget)
+    mTexTarget(texTarget),
+    mAbandoned(false),
+    mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT)
 {
+    // Choose a name using the PID and a process-unique ID.
+    mName = String8::format("unnamed-%d-%d", getpid(), createProcessUniqueId());
+    BufferQueue::setConsumerName(mName);
 
     ST_LOGV("SurfaceTexture");
     memcpy(mCurrentTransformMatrix, mtxIdentity,
@@ -118,28 +128,18 @@
 
 SurfaceTexture::~SurfaceTexture() {
     ST_LOGV("~SurfaceTexture");
-    freeAllBuffersLocked();
+    abandon();
 }
 
 status_t SurfaceTexture::setBufferCountServer(int bufferCount) {
     Mutex::Autolock lock(mMutex);
-    return setBufferCountServerLocked(bufferCount);
+    return BufferQueue::setBufferCountServer(bufferCount);
 }
 
 
 status_t SurfaceTexture::setDefaultBufferSize(uint32_t w, uint32_t h)
 {
-    ST_LOGV("setDefaultBufferSize: w=%d, h=%d", w, h);
-    if (!w || !h) {
-        ST_LOGE("setDefaultBufferSize: dimensions cannot be 0 (w=%d, h=%d)",
-                w, h);
-        return BAD_VALUE;
-    }
-
-    Mutex::Autolock lock(mMutex);
-    mDefaultWidth = w;
-    mDefaultHeight = h;
-    return OK;
+    return BufferQueue::setDefaultBufferSize(w, h);
 }
 
 status_t SurfaceTexture::updateTexImage() {
@@ -151,23 +151,35 @@
         return NO_INIT;
     }
 
+    BufferItem item;
+
     // In asynchronous mode the list is guaranteed to be one buffer
     // deep, while in synchronous mode we use the oldest buffer.
-    if (!mQueue.empty()) {
-        Fifo::iterator front(mQueue.begin());
-        int buf = *front;
+    if (acquire(&item) == NO_ERROR) {
+        int buf = item.mBuf;
+        // This buffer was newly allocated, so we need to clean up on our side
+        if (item.mGraphicBuffer != NULL) {
+            mEGLSlots[buf].mGraphicBuffer = 0;
+            if (mEGLSlots[buf].mEglImage != EGL_NO_IMAGE_KHR) {
+                eglDestroyImageKHR(mEGLSlots[buf].mEglDisplay,
+                        mEGLSlots[buf].mEglImage);
+                mEGLSlots[buf].mEglImage = EGL_NO_IMAGE_KHR;
+                mEGLSlots[buf].mEglDisplay = EGL_NO_DISPLAY;
+            }
+            mEGLSlots[buf].mGraphicBuffer = item.mGraphicBuffer;
+        }
 
         // Update the GL texture object.
-        EGLImageKHR image = mSlots[buf].mEglImage;
+        EGLImageKHR image = mEGLSlots[buf].mEglImage;
         EGLDisplay dpy = eglGetCurrentDisplay();
         if (image == EGL_NO_IMAGE_KHR) {
-            if (mSlots[buf].mGraphicBuffer == 0) {
+            if (item.mGraphicBuffer == 0) {
                 ST_LOGE("buffer at slot %d is null", buf);
                 return BAD_VALUE;
             }
-            image = createImage(dpy, mSlots[buf].mGraphicBuffer);
-            mSlots[buf].mEglImage = image;
-            mSlots[buf].mEglDisplay = dpy;
+            image = createImage(dpy, item.mGraphicBuffer);
+            mEGLSlots[buf].mEglImage = image;
+            mEGLSlots[buf].mEglDisplay = dpy;
             if (image == EGL_NO_IMAGE_KHR) {
                 // NOTE: if dpy was invalid, createImage() is guaranteed to
                 // fail. so we'd end up here.
@@ -190,6 +202,8 @@
             failed = true;
         }
         if (failed) {
+            releaseBuffer(buf, mEGLSlots[buf].mEglDisplay,
+                    mEGLSlots[buf].mFence);
             return -EINVAL;
         }
 
@@ -200,40 +214,37 @@
                 if (fence == EGL_NO_SYNC_KHR) {
                     ALOGE("updateTexImage: error creating fence: %#x",
                             eglGetError());
+                    releaseBuffer(buf, mEGLSlots[buf].mEglDisplay,
+                            mEGLSlots[buf].mFence);
                     return -EINVAL;
                 }
                 glFlush();
-                mSlots[mCurrentTexture].mFence = fence;
+                mEGLSlots[mCurrentTexture].mFence = fence;
             }
         }
 
         ST_LOGV("updateTexImage: (slot=%d buf=%p) -> (slot=%d buf=%p)",
                 mCurrentTexture,
                 mCurrentTextureBuf != NULL ? mCurrentTextureBuf->handle : 0,
-                buf, mSlots[buf].mGraphicBuffer->handle);
+                buf, item.mGraphicBuffer != NULL ? item.mGraphicBuffer->handle : 0);
 
-        if (mCurrentTexture != INVALID_BUFFER_SLOT) {
-            // The current buffer becomes FREE if it was still in the queued
-            // state. If it has already been given to the client
-            // (synchronous mode), then it stays in DEQUEUED state.
-            if (mSlots[mCurrentTexture].mBufferState == BufferSlot::QUEUED) {
-                mSlots[mCurrentTexture].mBufferState = BufferSlot::FREE;
-            }
-        }
+        // release old buffer
+        releaseBuffer(mCurrentTexture,
+                mEGLSlots[mCurrentTexture].mEglDisplay,
+                mEGLSlots[mCurrentTexture].mFence);
 
         // Update the SurfaceTexture state.
         mCurrentTexture = buf;
-        mCurrentTextureBuf = mSlots[buf].mGraphicBuffer;
-        mCurrentCrop = mSlots[buf].mCrop;
-        mCurrentTransform = mSlots[buf].mTransform;
-        mCurrentScalingMode = mSlots[buf].mScalingMode;
-        mCurrentTimestamp = mSlots[buf].mTimestamp;
+        mCurrentTextureBuf = mEGLSlots[buf].mGraphicBuffer;
+        mCurrentCrop = item.mCrop;
+        mCurrentTransform = item.mTransform;
+        mCurrentScalingMode = item.mScalingMode;
+        mCurrentTimestamp = item.mTimestamp;
         computeCurrentTransformMatrix();
 
         // Now that we've passed the point at which failures can happen,
         // it's safe to remove the buffer from the front of the queue.
-        mQueue.erase(front);
-        mDequeueCondition.signal();
+
     } else {
         // We always bind the texture even if we don't update its contents.
         glBindTexture(mTexTarget, mTexName);
@@ -299,7 +310,7 @@
         }
     }
 
-    sp<GraphicBuffer>& buf(mSlots[mCurrentTexture].mGraphicBuffer);
+    sp<GraphicBuffer>& buf(mCurrentTextureBuf);
     float tx, ty, sx, sy;
     if (!mCurrentCrop.isEmpty()) {
         // In order to prevent bilinear sampling at the of the crop rectangle we
@@ -371,7 +382,7 @@
         const sp<FrameAvailableListener>& listener) {
     ST_LOGV("setFrameAvailableListener");
     Mutex::Autolock lock(mMutex);
-    mFrameAvailableListener = listener;
+    BufferQueue::setFrameAvailableListener(listener);
 }
 
 EGLImageKHR SurfaceTexture::createImage(EGLDisplay dpy,
@@ -412,22 +423,33 @@
 
 bool SurfaceTexture::isSynchronousMode() const {
     Mutex::Autolock lock(mMutex);
-    return mSynchronousMode;
+    return BufferQueue::isSynchronousMode();
 }
 
-
-
 void SurfaceTexture::abandon() {
     Mutex::Autolock lock(mMutex);
-    mQueue.clear();
     mAbandoned = true;
     mCurrentTextureBuf.clear();
-    freeAllBuffersLocked();
-    mDequeueCondition.signal();
+
+    // destroy all egl buffers
+    for (int i =0; i < NUM_BUFFER_SLOTS; i++) {
+        mEGLSlots[i].mGraphicBuffer = 0;
+        if (mEGLSlots[i].mEglImage != EGL_NO_IMAGE_KHR) {
+            eglDestroyImageKHR(mEGLSlots[i].mEglDisplay,
+                    mEGLSlots[i].mEglImage);
+            mEGLSlots[i].mEglImage = EGL_NO_IMAGE_KHR;
+            mEGLSlots[i].mEglDisplay = EGL_NO_DISPLAY;
+        }
+    }
+
+    // disconnect from the BufferQueue
+    BufferQueue::consumerDisconnect();
 }
 
 void SurfaceTexture::setName(const String8& name) {
+    Mutex::Autolock _l(mMutex);
     mName = name;
+    BufferQueue::setConsumerName(name);
 }
 
 void SurfaceTexture::dump(String8& result) const
@@ -440,68 +462,19 @@
         char* buffer, size_t SIZE) const
 {
     Mutex::Autolock _l(mMutex);
-    snprintf(buffer, SIZE,
-            "%smBufferCount=%d, mSynchronousMode=%d, default-size=[%dx%d], "
-            "mPixelFormat=%d, mTexName=%d\n",
-            prefix, mBufferCount, mSynchronousMode, mDefaultWidth,
-            mDefaultHeight, mPixelFormat, mTexName);
+    snprintf(buffer, SIZE, "%smTexName=%d\n", prefix, mTexName);
     result.append(buffer);
 
-    String8 fifo;
-    int fifoSize = 0;
-    Fifo::const_iterator i(mQueue.begin());
-    while (i != mQueue.end()) {
-        snprintf(buffer, SIZE, "%02d ", *i++);
-        fifoSize++;
-        fifo.append(buffer);
-    }
-
     snprintf(buffer, SIZE,
-            "%scurrent: {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n"
-            "%snext   : {crop=[%d,%d,%d,%d], transform=0x%02x, FIFO(%d)={%s}}\n"
-            ,
-            prefix, mCurrentCrop.left,
+            "%snext   : {crop=[%d,%d,%d,%d], transform=0x%02x, current=%d}\n"
+            ,prefix, mCurrentCrop.left,
             mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
-            mCurrentTransform, mCurrentTexture,
-            prefix, mNextCrop.left, mNextCrop.top, mNextCrop.right,
-            mNextCrop.bottom, mNextTransform, fifoSize, fifo.string()
+            mCurrentTransform, mCurrentTexture
     );
     result.append(buffer);
 
-    struct {
-        const char * operator()(int state) const {
-            switch (state) {
-                case BufferSlot::DEQUEUED: return "DEQUEUED";
-                case BufferSlot::QUEUED: return "QUEUED";
-                case BufferSlot::FREE: return "FREE";
-                default: return "Unknown";
-            }
-        }
-    } stateName;
 
-    for (int i=0 ; i<mBufferCount ; i++) {
-        const BufferSlot& slot(mSlots[i]);
-        snprintf(buffer, SIZE,
-                "%s%s[%02d] "
-                "state=%-8s, crop=[%d,%d,%d,%d], "
-                "transform=0x%02x, timestamp=%lld",
-                prefix, (i==mCurrentTexture)?">":" ", i,
-                stateName(slot.mBufferState),
-                slot.mCrop.left, slot.mCrop.top, slot.mCrop.right,
-                slot.mCrop.bottom, slot.mTransform, slot.mTimestamp
-        );
-        result.append(buffer);
-
-        const sp<GraphicBuffer>& buf(slot.mGraphicBuffer);
-        if (buf != NULL) {
-            snprintf(buffer, SIZE,
-                    ", %p [%4ux%4u:%4u,%3X]",
-                    buf->handle, buf->width, buf->height, buf->stride,
-                    buf->format);
-            result.append(buffer);
-        }
-        result.append("\n");
-    }
+    BufferQueue::dump(result, prefix, buffer, SIZE);
 }
 
 static void mtxMul(float out[16], const float a[16], const float b[16]) {
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index 098a1a2..dc27d38 100755
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -845,6 +845,17 @@
          config->inputCfg.samplingRate, config->inputCfg.channels);
     int status;
 
+    // if at least one process is enabled, do not accept configuration changes
+    if (session->enabledMsk) {
+        if (session->samplingRate != config->inputCfg.samplingRate ||
+                session->inChannelCount != inCnl ||
+                session->outChannelCount != outCnl) {
+            return -ENOSYS;
+        } else {
+            return 0;
+        }
+    }
+
     // AEC implementation is limited to 16kHz
     if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
         session->apmSamplingRate = 32000;
@@ -1287,7 +1298,9 @@
             if (*(int *)pReplyData != 0) {
                 break;
             }
-            *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
+            if (effect->state != PREPROC_EFFECT_STATE_ACTIVE) {
+                *(int *)pReplyData = Effect_SetState(effect, PREPROC_EFFECT_STATE_CONFIG);
+            }
             break;
 
         case EFFECT_CMD_GET_CONFIG:
diff --git a/media/libstagefright/colorconversion/SoftwareRenderer.cpp b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
index b8516afd..059d6b9 100644
--- a/media/libstagefright/colorconversion/SoftwareRenderer.cpp
+++ b/media/libstagefright/colorconversion/SoftwareRenderer.cpp
@@ -19,8 +19,6 @@
 
 #include "../include/SoftwareRenderer.h"
 
-#include <binder/MemoryHeapBase.h>
-#include <binder/MemoryHeapPmem.h>
 #include <media/stagefright/foundation/ADebug.h>
 #include <media/stagefright/MetaData.h>
 #include <system/window.h>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index 3a2ea65..a08b99a 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -22,7 +22,6 @@
     <drawable name="notification_item_background_color_pressed">#ff257390</drawable>
     <drawable name="ticker_background_color">#ff1d1d1d</drawable>
     <drawable name="status_bar_background">#ff000000</drawable>
-    <drawable name="status_bar_recents_background_solid">#b3000000</drawable>
     <drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable>
     <color name="status_bar_recents_app_label_color">#ffffffff</color>
     <drawable name="status_bar_notification_row_background_color">#ff090909</drawable>
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
index 78050a2..deb5670 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsCallback.java
@@ -27,9 +27,5 @@
     void handleOnClick(View selectedView);
     void handleSwipe(View selectedView);
     void handleLongPress(View selectedView, View anchorView, View thumbnailView);
-    void handleShowBackground(boolean show);
     void dismiss();
-
-    // TODO: find another way to get this info from RecentsPanelView
-    boolean isRecentsVisible();
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
index 4dc3e33..76e6ee8 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsHorizontalScrollView.java
@@ -217,14 +217,6 @@
     }
 
     @Override
-    protected void onLayout (boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        if (mPerformanceHelper != null) {
-            mPerformanceHelper.onLayoutCallback();
-        }
-    }
-
-    @Override
     public void draw(Canvas canvas) {
         super.draw(canvas);
 
@@ -327,12 +319,6 @@
         });
     }
 
-    public void onRecentsVisibilityChanged() {
-        if (mPerformanceHelper != null) {
-            mPerformanceHelper.updateShowBackground();
-        }
-    }
-
     @Override
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
@@ -379,9 +365,6 @@
 
     @Override
     public void setLayoutTransition(LayoutTransition transition) {
-        if (mPerformanceHelper != null) {
-            mPerformanceHelper.setLayoutTransitionCallback(transition);
-        }
         // The layout transition applies to our embedded LinearLayout
         mLinearLayout.setLayoutTransition(transition);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
index 7896720..18132ff 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsPanelView.java
@@ -32,13 +32,14 @@
 import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.Display;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
 import android.view.MenuItem;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewRootImpl;
+import android.view.WindowManager;
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
 import android.widget.AdapterView;
@@ -325,18 +326,6 @@
         }
     }
 
-    public void handleShowBackground(boolean show) {
-        if (show) {
-            mRecentsScrim.setBackgroundResource(R.drawable.status_bar_recents_background_solid);
-        } else {
-            mRecentsScrim.setBackgroundDrawable(null);
-        }
-    }
-
-    public boolean isRecentsVisible() {
-        return getVisibility() == VISIBLE;
-    }
-
     public void onAnimationCancel(Animator animation) {
     }
 
@@ -457,9 +446,15 @@
         mRecentsNoApps = findViewById(R.id.recents_no_apps);
         mChoreo = new Choreographer(this, mRecentsScrim, mRecentsContainer, mRecentsNoApps, this);
 
-        // In order to save space, we make the background texture repeat in the Y direction
-        if (mRecentsScrim != null && mRecentsScrim.getBackground() instanceof BitmapDrawable) {
-            ((BitmapDrawable) mRecentsScrim.getBackground()).setTileModeY(TileMode.REPEAT);
+        if (mRecentsScrim != null) {
+            Display d = ((WindowManager)mContext.getSystemService(Context.WINDOW_SERVICE))
+                .getDefaultDisplay();
+            if (!ActivityManager.isHighEndGfx(d)) {
+                mRecentsScrim.setBackgroundDrawable(null);
+            } else if (mRecentsScrim.getBackground() instanceof BitmapDrawable) {
+                // In order to save space, we make the background texture repeat in the Y direction
+                ((BitmapDrawable) mRecentsScrim.getBackground()).setTileModeY(TileMode.REPEAT);
+            }
         }
 
         mPreloadTasksRunnable = new Runnable() {
@@ -478,21 +473,6 @@
         transitioner.setAnimator(LayoutTransition.DISAPPEARING, null);
     }
 
-    @Override
-    protected void onVisibilityChanged(View changedView, int visibility) {
-        super.onVisibilityChanged(changedView, visibility);
-        if (DEBUG) Log.v(TAG, "onVisibilityChanged(" + changedView + ", " + visibility + ")");
-
-        if (mRecentsContainer instanceof RecentsHorizontalScrollView) {
-            ((RecentsHorizontalScrollView) mRecentsContainer).onRecentsVisibilityChanged();
-        } else if (mRecentsContainer instanceof RecentsVerticalScrollView) {
-            ((RecentsVerticalScrollView) mRecentsContainer).onRecentsVisibilityChanged();
-        } else {
-            throw new IllegalArgumentException("missing Recents[Horizontal]ScrollView");
-        }
-    }
-
-
     private void updateIcon(ViewHolder h, Drawable icon, boolean show, boolean anim) {
         if (icon != null) {
             h.iconView.setImageDrawable(icon);
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
index 813099a..5529d0c 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsScrollViewPerformanceHelper.java
@@ -78,39 +78,13 @@
             mScrollView.setVerticalFadingEdgeEnabled(false);
             mScrollView.setHorizontalFadingEdgeEnabled(false);
         }
-        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
-            mCallback = callback;
-            mLinearLayout = layout;
-            mAttachedToWindow = true;
-            mBackgroundDrawable = mContext.getResources()
-                .getDrawable(R.drawable.status_bar_recents_background_solid).getConstantState();
-            updateShowBackground();
-        }
-
     }
 
     public void addViewCallback(View newLinearLayoutChild) {
         if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
             final View view = newLinearLayoutChild;
-            if (mShowBackground) {
-                view.setBackgroundDrawable(mBackgroundDrawable.newDrawable());
-                view.setDrawingCacheEnabled(true);
-                view.buildDrawingCache();
-            } else {
-                view.setBackgroundDrawable(null);
-                view.setDrawingCacheEnabled(false);
-                view.destroyDrawingCache();
-            }
-        }
-    }
-
-    public void onLayoutCallback() {
-        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
-            mScrollView.post(new Runnable() {
-                public void run() {
-                    updateShowBackground();
-                }
-            });
+            view.setDrawingCacheEnabled(true);
+            view.buildDrawingCache();
         }
     }
 
@@ -118,37 +92,6 @@
             int left, int right, int top, int bottom, int scrollX, int scrollY,
             float topFadingEdgeStrength, float bottomFadingEdgeStrength,
             float leftFadingEdgeStrength, float rightFadingEdgeStrength) {
-        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
-            if (mIsVertical) {
-                if (scrollY < 0) {
-                    Drawable d = mBackgroundDrawable.newDrawable().getCurrent();
-                    d.setBounds(0, scrollY, mScrollView.getWidth(), 0);
-                    d.draw(canvas);
-                } else {
-                    final int childHeight = mLinearLayout.getHeight();
-                    if (scrollY + mScrollView.getHeight() > childHeight) {
-                        Drawable d = mBackgroundDrawable.newDrawable().getCurrent();
-                        d.setBounds(0, childHeight, mScrollView.getWidth(),
-                                scrollY + mScrollView.getHeight());
-                        d.draw(canvas);
-                    }
-                }
-            } else {
-                if (scrollX < 0) {
-                    Drawable d = mBackgroundDrawable.newDrawable().getCurrent();
-                    d.setBounds(scrollX, 0, 0, mScrollView.getHeight());
-                    d.draw(canvas);
-                } else {
-                    final int childWidth = mLinearLayout.getWidth();
-                    if (scrollX + mScrollView.getWidth() > childWidth) {
-                        Drawable d = mBackgroundDrawable.newDrawable().getCurrent();
-                        d.setBounds(childWidth, 0,
-                                scrollX + mScrollView.getWidth(), mScrollView.getHeight());
-                        d.draw(canvas);
-                    }
-                }
-            }
-        }
 
         if ((mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS)
                 || USE_DARK_FADE_IN_HW_ACCELERATED_MODE) {
@@ -241,64 +184,4 @@
         return mFadingEdgeLength;
     }
 
-    public void setLayoutTransitionCallback(LayoutTransition transition) {
-        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
-            if (transition != null) {
-                transition.addTransitionListener(new LayoutTransition.TransitionListener() {
-                    @Override
-                    public void startTransition(LayoutTransition transition,
-                            ViewGroup container, View view, int transitionType) {
-                        updateShowBackground();
-                    }
-
-                    @Override
-                    public void endTransition(LayoutTransition transition,
-                            ViewGroup container, View view, int transitionType) {
-                        updateShowBackground();
-                    }
-                });
-            }
-        }
-    }
-
-    // Turn on/off drawing the background in our ancestor, and turn on/off drawing
-    // in the items in LinearLayout contained by this scrollview.
-    // Moving the background drawing to our children, and turning on a drawing cache
-    // for each of them, gives us a ~20fps gain when Recents is rendered in software
-    public void updateShowBackground() {
-        if (!mAttachedToWindow) {
-            // We haven't been initialized yet-- we'll get called again when we are
-            return;
-        }
-        if (mSoftwareRendered && OPTIMIZE_SW_RENDERED_RECENTS) {
-            LayoutTransition transition = mLinearLayout.getLayoutTransition();
-            int linearLayoutSize =
-                mIsVertical ? mLinearLayout.getHeight() : mLinearLayout.getWidth();
-            int scrollViewSize =
-                mIsVertical ? mScrollView.getHeight() : mScrollView.getWidth();
-            boolean show = !mScrollView.isHardwareAccelerated() &&
-                (linearLayoutSize > scrollViewSize) &&
-                !(transition != null && transition.isRunning()) &&
-                mCallback.isRecentsVisible();
-
-            if (!mFirstTime && show == mShowBackground) return;
-            mShowBackground = show;
-            mFirstTime = false;
-
-            mCallback.handleShowBackground(!show);
-            for (int i = 0; i < mLinearLayout.getChildCount(); i++) {
-                View v = mLinearLayout.getChildAt(i);
-                if (show) {
-                    v.setBackgroundDrawable(mBackgroundDrawable.newDrawable());
-                    v.setDrawingCacheEnabled(true);
-                    v.buildDrawingCache();
-                } else {
-                    v.setDrawingCacheEnabled(false);
-                    v.destroyDrawingCache();
-                    v.setBackgroundDrawable(null);
-                }
-            }
-        }
-    }
-
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
index 19fce37..1bfd000 100644
--- a/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/recent/RecentsVerticalScrollView.java
@@ -224,14 +224,6 @@
     }
 
     @Override
-    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        super.onLayout(changed, left, top, right, bottom);
-        if (mPerformanceHelper != null) {
-            mPerformanceHelper.onLayoutCallback();
-        }
-    }
-
-    @Override
     public void draw(Canvas canvas) {
         super.draw(canvas);
 
@@ -334,12 +326,6 @@
         });
     }
 
-    public void onRecentsVisibilityChanged() {
-        if (mPerformanceHelper != null) {
-            mPerformanceHelper.updateShowBackground();
-        }
-    }
-
     @Override
     protected void onVisibilityChanged(View changedView, int visibility) {
         super.onVisibilityChanged(changedView, visibility);
@@ -387,9 +373,6 @@
 
     @Override
     public void setLayoutTransition(LayoutTransition transition) {
-        if (mPerformanceHelper != null) {
-            mPerformanceHelper.setLayoutTransitionCallback(transition);
-        }
         // The layout transition applies to our embedded LinearLayout
         mLinearLayout.setLayoutTransition(transition);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 2458495..b2d9e64 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -397,6 +397,9 @@
                 (opaque ? PixelFormat.OPAQUE : PixelFormat.TRANSLUCENT));
         if (ActivityManager.isHighEndGfx(mDisplay)) {
             lp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+        } else {
+            lp.flags |= WindowManager.LayoutParams.FLAG_DIM_BEHIND;
+            lp.dimAmount = 0.7f;
         }
         lp.gravity = Gravity.BOTTOM | Gravity.LEFT;
         lp.setTitle("RecentsPanel");
diff --git a/packages/VpnDialogs/res/layout/manage.xml b/packages/VpnDialogs/res/layout/manage.xml
index ec710ff..56332c3 100644
--- a/packages/VpnDialogs/res/layout/manage.xml
+++ b/packages/VpnDialogs/res/layout/manage.xml
@@ -32,12 +32,12 @@
         <TextView android:id="@+id/duration" style="@style/value"/>
     </TableRow>
 
-    <TableRow>
+    <TableRow android:id="@+id/data_transmitted_row" android:visibility="gone">
         <TextView android:text="@string/data_transmitted" style="@style/label"/>
         <TextView android:id="@+id/data_transmitted" style="@style/value"/>
     </TableRow>
 
-    <TableRow>
+    <TableRow android:id="@+id/data_received_row" android:visibility="gone">
         <TextView android:text="@string/data_received" style="@style/label"/>
         <TextView android:id="@+id/data_received" style="@style/value"/>
     </TableRow>
diff --git a/packages/VpnDialogs/res/values/strings.xml b/packages/VpnDialogs/res/values/strings.xml
index 1352e9b..3ff767a 100644
--- a/packages/VpnDialogs/res/values/strings.xml
+++ b/packages/VpnDialogs/res/values/strings.xml
@@ -48,8 +48,6 @@
     <!-- Label for the network usage of data received over VPN. [CHAR LIMIT=20] -->
     <string name="data_received">Received:</string>
 
-    <!-- Dummy string for a blank value. [CHAR LIMIT=40] -->
-    <string name="blank_value">--</string>
     <!-- Formatted string for the network usage over VPN. [CHAR LIMIT=40] -->
     <string name="data_value_format">
         <xliff:g id="number">%1$s</xliff:g> bytes /
diff --git a/packages/VpnDialogs/res/values/styles.xml b/packages/VpnDialogs/res/values/styles.xml
index e3469ec..0dda673 100644
--- a/packages/VpnDialogs/res/values/styles.xml
+++ b/packages/VpnDialogs/res/values/styles.xml
@@ -25,6 +25,5 @@
         <item name="android:gravity">center_vertical|left</item>
         <item name="android:textSize">18sp</item>
         <item name="android:textStyle">bold</item>
-        <item name="android:text">@string/blank_value</item>
     </style>
 </resources>
diff --git a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
index 2de0251..9999adb1 100644
--- a/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
+++ b/packages/VpnDialogs/src/com/android/vpndialogs/ManageDialog.java
@@ -50,6 +50,7 @@
     private TextView mDuration;
     private TextView mDataTransmitted;
     private TextView mDataReceived;
+    private boolean mDataRowsHidden;
 
     private Handler mHandler;
 
@@ -76,6 +77,7 @@
             mDuration = (TextView) view.findViewById(R.id.duration);
             mDataTransmitted = (TextView) view.findViewById(R.id.data_transmitted);
             mDataReceived = (TextView) view.findViewById(R.id.data_received);
+            mDataRowsHidden = true;
 
             if (mConfig.user.equals(VpnConfig.LEGACY_VPN)) {
                 mAlertParams.mIconId = android.R.drawable.ic_dialog_info;
@@ -140,8 +142,15 @@
                         seconds / 3600, seconds / 60 % 60, seconds % 60));
             }
 
-            String[] numbers = getStatistics();
+            String[] numbers = getNumbers();
             if (numbers != null) {
+                // First unhide the related data rows.
+                if (mDataRowsHidden) {
+                    findViewById(R.id.data_transmitted_row).setVisibility(View.VISIBLE);
+                    findViewById(R.id.data_received_row).setVisibility(View.VISIBLE);
+                    mDataRowsHidden = false;
+                }
+
                 // [1] and [2] are received data in bytes and packets.
                 mDataReceived.setText(getString(R.string.data_value_format,
                         numbers[1], numbers[2]));
@@ -155,7 +164,7 @@
         return true;
     }
 
-    private String[] getStatistics() {
+    private String[] getNumbers() {
         DataInputStream in = null;
         try {
             // See dev_seq_printf_stats() in net/core/dev.c.
diff --git a/services/java/com/android/server/BootReceiver.java b/services/java/com/android/server/BootReceiver.java
index 6665614..da65438 100644
--- a/services/java/com/android/server/BootReceiver.java
+++ b/services/java/com/android/server/BootReceiver.java
@@ -39,8 +39,10 @@
 public class BootReceiver extends BroadcastReceiver {
     private static final String TAG = "BootReceiver";
 
-    // Maximum size of a logged event (files get truncated if they're longer)
-    private static final int LOG_SIZE = 65536;
+    // Maximum size of a logged event (files get truncated if they're longer).
+    // Give userdebug builds a larger max to capture extra debug, esp. for last_kmsg.
+    private static final int LOG_SIZE =
+        SystemProperties.getInt("ro.debuggable", 0) == 1 ? 98304 : 65536;
 
     private static final File TOMBSTONE_DIR = new File("/data/tombstones");