Merge "Clarify some android-specific OMX extensions for native buffers."
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 38b0b24..7710c5b 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -95,6 +95,7 @@
 
     run_command("PROCESSES", 10, "ps", "-P", NULL);
     run_command("PROCESSES AND THREADS", 10, "ps", "-t", "-p", "-P", NULL);
+    run_command("PROCESSES (SELINUX LABELS)", 10, "ps", "-Z", NULL);
     run_command("LIBRANK", 10, "librank", NULL);
 
     do_dmesg();
@@ -285,7 +286,7 @@
     run_command("CHECKIN MEMINFO", 30, "dumpsys", "meminfo", "--checkin", NULL);
     run_command("CHECKIN NETSTATS", 30, "dumpsys", "netstats", "--checkin", NULL);
     run_command("CHECKIN PROCSTATS", 30, "dumpsys", "procstats", "-c", NULL);
-    run_command("CHECKIN USAGESTATS", 30, "dumpsys", "usagestats", "--c", NULL);
+    run_command("CHECKIN USAGESTATS", 30, "dumpsys", "usagestats", "-c", NULL);
 
     printf("========================================================\n");
     printf("== Running Application Activities\n");
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index 4f7697f..89eb95f 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -199,8 +199,8 @@
 bool GLHelper::createNamedSurfaceTexture(GLuint name, uint32_t w, uint32_t h,
         sp<GLConsumer>* glConsumer, EGLSurface* surface) {
     sp<BufferQueue> bq = new BufferQueue(true, mGraphicBufferAlloc);
-    sp<GLConsumer> glc = new GLConsumer(name, true,
-            GL_TEXTURE_EXTERNAL_OES, false, bq);
+    sp<GLConsumer> glc = new GLConsumer(bq, name,
+            GL_TEXTURE_EXTERNAL_OES, false);
     glc->setDefaultBufferSize(w, h);
     glc->setDefaultMaxBufferCount(3);
     glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
diff --git a/cmds/inputflinger/Android.mk b/cmds/inputflinger/Android.mk
new file mode 100644
index 0000000..b44de44
--- /dev/null
+++ b/cmds/inputflinger/Android.mk
@@ -0,0 +1,28 @@
+# Copyright (C) 2013 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	main.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libbinder \
+	libinputflinger \
+	libutils
+
+LOCAL_MODULE := inputflinger
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/inputflinger/main.cpp b/cmds/inputflinger/main.cpp
new file mode 100644
index 0000000..6de7b24
--- /dev/null
+++ b/cmds/inputflinger/main.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <binder/BinderService.h>
+#include <InputFlinger.h>
+
+using namespace android;
+
+int main(int argc, char** argv) {
+    ProcessState::self()->setThreadPoolMaxThreadCount(4);
+    BinderService<InputFlinger>::publishAndJoinThreadPool(true);
+    return 0;
+}
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 27580f3..84ad204 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -108,11 +108,11 @@
     return 0;
 }
 
-int uninstall(const char *pkgname, uid_t persona)
+int uninstall(const char *pkgname, userid_t userid)
 {
     char pkgdir[PKG_PATH_MAX];
 
-    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
+    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid))
         return -1;
 
     /* delete contents AND directory, no exceptions */
@@ -173,18 +173,18 @@
     return 0;
 }
 
-int delete_user_data(const char *pkgname, uid_t persona)
+int delete_user_data(const char *pkgname, userid_t userid)
 {
     char pkgdir[PKG_PATH_MAX];
 
-    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona))
+    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid))
         return -1;
 
     /* delete contents, excluding "lib", but not the directory itself */
     return delete_dir_contents(pkgdir, 0, "lib");
 }
 
-int make_user_data(const char *pkgname, uid_t uid, uid_t persona)
+int make_user_data(const char *pkgname, uid_t uid, userid_t userid)
 {
     char pkgdir[PKG_PATH_MAX];
     char applibdir[PKG_PATH_MAX];
@@ -192,10 +192,10 @@
     struct stat libStat;
 
     // Create the data dir for the package
-    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, persona)) {
+    if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid)) {
         return -1;
     }
-    if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, persona)) {
+    if (create_pkg_path(libsymlink, pkgname, PKG_LIB_POSTFIX, userid)) {
         ALOGE("cannot create package lib symlink origin path\n");
         return -1;
     }
@@ -262,10 +262,10 @@
     return 0;
 }
 
-int delete_persona(uid_t persona)
+int delete_user(userid_t userid)
 {
     char data_path[PKG_PATH_MAX];
-    if (create_persona_path(data_path, persona)) {
+    if (create_user_path(data_path, userid)) {
         return -1;
     }
     if (delete_dir_contents(data_path, 1, NULL)) {
@@ -273,7 +273,7 @@
     }
 
     char media_path[PATH_MAX];
-    if (create_persona_media_path(media_path, (userid_t) persona) == -1) {
+    if (create_user_media_path(media_path, userid) == -1) {
         return -1;
     }
     if (delete_dir_contents(media_path, 1, NULL) == -1) {
@@ -283,11 +283,11 @@
     return 0;
 }
 
-int delete_cache(const char *pkgname, uid_t persona)
+int delete_cache(const char *pkgname, userid_t userid)
 {
     char cachedir[PKG_PATH_MAX];
 
-    if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, persona))
+    if (create_pkg_path(cachedir, pkgname, CACHE_DIR_POSTFIX, userid))
         return -1;
 
         /* delete contents, not the directory, no exceptions */
@@ -319,7 +319,7 @@
     cache = start_cache_collection();
 
     // Collect cache files for primary user.
-    if (create_persona_path(tmpdir, 0) == 0) {
+    if (create_user_path(tmpdir, 0) == 0) {
         //ALOGI("adding cache files from %s\n", tmpdir);
         add_cache_files(cache, tmpdir, "cache");
     }
@@ -420,7 +420,7 @@
     }
 }
 
-int get_size(const char *pkgname, int persona, const char *apkpath,
+int get_size(const char *pkgname, userid_t userid, const char *apkpath,
              const char *libdirpath, const char *fwdlock_apkpath, const char *asecpath,
              int64_t *_codesize, int64_t *_datasize, int64_t *_cachesize,
              int64_t* _asecsize)
@@ -477,7 +477,7 @@
         }
     }
 
-    if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, persona)) {
+    if (create_pkg_path(path, pkgname, PKG_DIR_POSTFIX, userid)) {
         goto done;
     }
 
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 87f900a..1904408 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -83,7 +83,7 @@
     int64_t asecsize = 0;
     int res = 0;
 
-        /* pkgdir, persona, apkpath */
+        /* pkgdir, userid, apkpath */
     res = get_size(arg[0], atoi(arg[1]), arg[2], arg[3], arg[4], arg[5],
             &codesize, &datasize, &cachesize, &asecsize);
 
@@ -108,7 +108,7 @@
 
 static int do_rm_user(char **arg, char reply[REPLY_MAX])
 {
-    return delete_persona(atoi(arg[0])); /* userid */
+    return delete_user(atoi(arg[0])); /* userid */
 }
 
 static int do_movefiles(char **arg, char reply[REPLY_MAX])
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index fbfc876..635b07c 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -78,9 +78,6 @@
 #define PKG_NAME_MAX  128   /* largest allowed package name */
 #define PKG_PATH_MAX  256   /* max size of any path we use */
 
-#define PER_USER_RANGE ((uid_t)100000)   /* range of uids per user
-                                            uid = persona * PER_USER_RANGE + appid */
-
 /* data structures */
 
 typedef struct {
@@ -138,17 +135,17 @@
 int create_pkg_path(char path[PKG_PATH_MAX],
                     const char *pkgname,
                     const char *postfix,
-                    uid_t persona);
+                    userid_t userid);
 
-int create_persona_path(char path[PKG_PATH_MAX],
-                    uid_t persona);
+int create_user_path(char path[PKG_PATH_MAX],
+                    userid_t userid);
 
-int create_persona_media_path(char path[PKG_PATH_MAX], userid_t userid);
+int create_user_media_path(char path[PKG_PATH_MAX], userid_t userid);
 
 int create_move_path(char path[PKG_PATH_MAX],
                      const char* pkgname,
                      const char* leaf,
-                     uid_t persona);
+                     userid_t userid);
 
 int is_valid_package_name(const char* pkgname);
 
@@ -193,17 +190,17 @@
 /* commands.c */
 
 int install(const char *pkgname, uid_t uid, gid_t gid, const char *seinfo);
-int uninstall(const char *pkgname, uid_t persona);
+int uninstall(const char *pkgname, userid_t userid);
 int renamepkg(const char *oldpkgname, const char *newpkgname);
 int fix_uid(const char *pkgname, uid_t uid, gid_t gid);
-int delete_user_data(const char *pkgname, uid_t persona);
-int make_user_data(const char *pkgname, uid_t uid, uid_t persona);
-int delete_persona(uid_t persona);
-int delete_cache(const char *pkgname, uid_t persona);
+int delete_user_data(const char *pkgname, userid_t userid);
+int make_user_data(const char *pkgname, uid_t uid, userid_t userid);
+int delete_user(userid_t userid);
+int delete_cache(const char *pkgname, userid_t userid);
 int move_dex(const char *src, const char *dst);
 int rm_dex(const char *path);
 int protect(char *pkgname, gid_t gid);
-int get_size(const char *pkgname, int persona, const char *apkpath, const char *libdirpath,
+int get_size(const char *pkgname, userid_t userid, const char *apkpath, const char *libdirpath,
              const char *fwdlock_apkpath, const char *asecpath, int64_t *codesize,
              int64_t *datasize, int64_t *cachesize, int64_t *asecsize);
 int free_cache(int64_t free_size);
diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp
index 7cb9b37..0b182af 100644
--- a/cmds/installd/tests/installd_utils_test.cpp
+++ b/cmds/installd/tests/installd_utils_test.cpp
@@ -340,7 +340,7 @@
 TEST_F(UtilsTest, CreatePersonaPath_Primary) {
     char path[PKG_PATH_MAX];
 
-    EXPECT_EQ(0, create_persona_path(path, 0))
+    EXPECT_EQ(0, create_user_path(path, 0))
             << "Should successfully build primary user path.";
 
     EXPECT_STREQ("/data/data/", path)
@@ -350,7 +350,7 @@
 TEST_F(UtilsTest, CreatePersonaPath_Secondary) {
     char path[PKG_PATH_MAX];
 
-    EXPECT_EQ(0, create_persona_path(path, 1))
+    EXPECT_EQ(0, create_user_path(path, 1))
             << "Should successfully build primary user path.";
 
     EXPECT_STREQ("/data/user/1/", path)
diff --git a/cmds/installd/utils.c b/cmds/installd/utils.c
index 625a35e..ef634c6 100644
--- a/cmds/installd/utils.c
+++ b/cmds/installd/utils.c
@@ -53,38 +53,39 @@
 
 /**
  * Create the package path name for a given package name with a postfix for
- * a certain persona. Returns 0 on success, and -1 on failure.
+ * a certain userid. Returns 0 on success, and -1 on failure.
  */
 int create_pkg_path(char path[PKG_PATH_MAX],
                     const char *pkgname,
                     const char *postfix,
-                    uid_t persona)
+                    userid_t userid)
 {
-    size_t uid_len;
-    char* persona_prefix;
-    if (persona == 0) {
-        persona_prefix = PRIMARY_USER_PREFIX;
-        uid_len = 0;
+    size_t userid_len;
+    char* userid_prefix;
+    if (userid == 0) {
+        userid_prefix = PRIMARY_USER_PREFIX;
+        userid_len = 0;
     } else {
-        persona_prefix = SECONDARY_USER_PREFIX;
-        uid_len = snprintf(NULL, 0, "%d", persona);
+        userid_prefix = SECONDARY_USER_PREFIX;
+        userid_len = snprintf(NULL, 0, "%d", userid);
     }
 
-    const size_t prefix_len = android_data_dir.len + strlen(persona_prefix) + uid_len + 1 /*slash*/;
+    const size_t prefix_len = android_data_dir.len + strlen(userid_prefix)
+            + userid_len + 1 /*slash*/;
     char prefix[prefix_len + 1];
 
     char *dst = prefix;
     size_t dst_size = sizeof(prefix);
 
     if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0
-            || append_and_increment(&dst, persona_prefix, &dst_size) < 0) {
+            || append_and_increment(&dst, userid_prefix, &dst_size) < 0) {
         ALOGE("Error building prefix for APK path");
         return -1;
     }
 
-    if (persona != 0) {
-        int ret = snprintf(dst, dst_size, "%d/", persona);
-        if (ret < 0 || (size_t) ret != uid_len + 1) {
+    if (userid != 0) {
+        int ret = snprintf(dst, dst_size, "%d/", userid);
+        if (ret < 0 || (size_t) ret != userid_len + 1) {
             ALOGW("Error appending UID to APK path");
             return -1;
         }
@@ -98,39 +99,39 @@
 }
 
 /**
- * Create the path name for user data for a certain persona.
+ * Create the path name for user data for a certain userid.
  * Returns 0 on success, and -1 on failure.
  */
-int create_persona_path(char path[PKG_PATH_MAX],
-                    uid_t persona)
+int create_user_path(char path[PKG_PATH_MAX],
+                    userid_t userid)
 {
-    size_t uid_len;
-    char* persona_prefix;
-    if (persona == 0) {
-        persona_prefix = PRIMARY_USER_PREFIX;
-        uid_len = 0;
+    size_t userid_len;
+    char* userid_prefix;
+    if (userid == 0) {
+        userid_prefix = PRIMARY_USER_PREFIX;
+        userid_len = 0;
     } else {
-        persona_prefix = SECONDARY_USER_PREFIX;
-        uid_len = snprintf(NULL, 0, "%d/", persona);
+        userid_prefix = SECONDARY_USER_PREFIX;
+        userid_len = snprintf(NULL, 0, "%d/", userid);
     }
 
     char *dst = path;
     size_t dst_size = PKG_PATH_MAX;
 
     if (append_and_increment(&dst, android_data_dir.path, &dst_size) < 0
-            || append_and_increment(&dst, persona_prefix, &dst_size) < 0) {
+            || append_and_increment(&dst, userid_prefix, &dst_size) < 0) {
         ALOGE("Error building prefix for user path");
         return -1;
     }
 
-    if (persona != 0) {
-        if (dst_size < uid_len + 1) {
+    if (userid != 0) {
+        if (dst_size < userid_len + 1) {
             ALOGE("Error building user path");
             return -1;
         }
-        int ret = snprintf(dst, dst_size, "%d/", persona);
-        if (ret < 0 || (size_t) ret != uid_len) {
-            ALOGE("Error appending persona id to path");
+        int ret = snprintf(dst, dst_size, "%d/", userid);
+        if (ret < 0 || (size_t) ret != userid_len) {
+            ALOGE("Error appending userid to path");
             return -1;
         }
     }
@@ -138,10 +139,10 @@
 }
 
 /**
- * Create the path name for media for a certain persona.
+ * Create the path name for media for a certain userid.
  * Returns 0 on success, and -1 on failure.
  */
-int create_persona_media_path(char path[PATH_MAX], userid_t userid) {
+int create_user_media_path(char path[PATH_MAX], userid_t userid) {
     if (snprintf(path, PATH_MAX, "%s%d", android_media_dir.path, userid) > PATH_MAX) {
         return -1;
     }
@@ -151,7 +152,7 @@
 int create_move_path(char path[PKG_PATH_MAX],
     const char* pkgname,
     const char* leaf,
-    uid_t persona)
+    userid_t userid)
 {
     if ((android_data_dir.len + strlen(PRIMARY_USER_PREFIX) + strlen(pkgname) + strlen(leaf) + 1)
             >= PKG_PATH_MAX) {
@@ -997,7 +998,7 @@
     char path[PATH_MAX];
 
     // Ensure /data/media/<userid> exists
-    create_persona_media_path(media_user_path, userid);
+    create_user_media_path(media_user_path, userid);
     if (fs_prepare_dir(media_user_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW) == -1) {
         return -1;
     }
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index cf38d1a..1ca1332 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -265,6 +265,7 @@
     AKEYCODE_ASSIST          = 219,
     AKEYCODE_BRIGHTNESS_DOWN = 220,
     AKEYCODE_BRIGHTNESS_UP   = 221,
+    AKEYCODE_MEDIA_AUDIO_TRACK = 222,
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h
index ad0daee..5bc123e 100644
--- a/include/binder/IPCThreadState.h
+++ b/include/binder/IPCThreadState.h
@@ -39,8 +39,8 @@
             
             status_t            clearLastError();
 
-            int                 getCallingPid();
-            int                 getCallingUid();
+            int                 getCallingPid() const;
+            int                 getCallingUid() const;
 
             void                setStrictModePolicy(int32_t policy);
             int32_t             getStrictModePolicy() const;
diff --git a/include/gui/BufferItemConsumer.h b/include/gui/BufferItemConsumer.h
index 5bf9acb..0af6f8e 100644
--- a/include/gui/BufferItemConsumer.h
+++ b/include/gui/BufferItemConsumer.h
@@ -29,6 +29,8 @@
 
 namespace android {
 
+class BufferQueue;
+
 /**
  * BufferItemConsumer is a BufferQueue consumer endpoint that allows clients
  * access to the whole BufferItem entry from BufferQueue. Multiple buffers may
@@ -49,7 +51,7 @@
     // the consumer usage flags passed to the graphics allocator. The
     // bufferCount parameter specifies how many buffers can be locked for user
     // access at the same time.
-    BufferItemConsumer(uint32_t consumerUsage,
+    BufferItemConsumer(const sp<BufferQueue>& bq, uint32_t consumerUsage,
             int bufferCount = BufferQueue::MIN_UNDEQUEUED_BUFFERS,
             bool synchronousMode = false);
 
diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h
index 3c178ef..5f1e369 100644
--- a/include/gui/CpuConsumer.h
+++ b/include/gui/CpuConsumer.h
@@ -28,6 +28,8 @@
 
 namespace android {
 
+class BufferQueue;
+
 /**
  * CpuConsumer is a BufferQueue consumer endpoint that allows direct CPU
  * access to the underlying gralloc buffers provided by BufferQueue. Multiple
@@ -64,7 +66,8 @@
 
     // Create a new CPU consumer. The maxLockedBuffers parameter specifies
     // how many buffers can be locked for user access at the same time.
-    CpuConsumer(uint32_t maxLockedBuffers, bool synchronousMode = true);
+    CpuConsumer(const sp<BufferQueue>& bq,
+            uint32_t maxLockedBuffers, bool synchronousMode = true);
 
     virtual ~CpuConsumer();
 
diff --git a/include/gui/GLConsumer.h b/include/gui/GLConsumer.h
index fbc8840..65544bd 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -85,9 +85,9 @@
     // purely to allow a GLConsumer to be transferred from one consumer
     // context to another. If such a transfer is not needed there is no
     // requirement that either of these methods be called.
-    GLConsumer(GLuint tex, bool allowSynchronousMode = true,
-            GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true,
-            const sp<BufferQueue> &bufferQueue = 0);
+    GLConsumer(const sp<BufferQueue>& bq,
+            GLuint tex, GLenum texTarget = GL_TEXTURE_EXTERNAL_OES,
+            bool useFenceSync = true);
 
     // updateTexImage acquires the most recently queued buffer, and sets the
     // image contents of the target texture to it.
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
new file mode 100644
index 0000000..79ff12a
--- /dev/null
+++ b/include/input/IInputFlinger.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _LIBINPUT_IINPUT_FLINGER_H
+#define _LIBINPUT_IINPUT_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+/*
+ * This class defines the Binder IPC interface for accessing various
+ * InputFlinger features.
+ */
+class IInputFlinger : public IInterface {
+public:
+    DECLARE_META_INTERFACE(InputFlinger);
+
+    virtual status_t doSomething() = 0;
+};
+
+
+/**
+ * Binder implementation.
+ */
+class BnInputFlinger : public BnInterface<IInputFlinger> {
+public:
+    enum {
+        DO_SOMETHING_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+    };
+
+    virtual status_t onTransact(uint32_t code, const Parcel& data,
+            Parcel* reply, uint32_t flags = 0);
+};
+
+} // namespace android
+
+#endif // _LIBINPUT_IINPUT_FLINGER_H
diff --git a/include/input/Input.h b/include/input/Input.h
index 6d49b18..e778076 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -28,10 +28,6 @@
 #include <utils/RefBase.h>
 #include <utils/String8.h>
 
-#ifdef HAVE_ANDROID_OS
-class SkMatrix;
-#endif
-
 /*
  * Additional private constants not defined in ndk/ui/input.h.
  */
@@ -529,9 +525,11 @@
 
     void scale(float scaleFactor);
 
-#ifdef HAVE_ANDROID_OS
-    void transform(const SkMatrix* matrix);
+    // Apply 3x3 perspective matrix transformation.
+    // Matrix is in row-major form and compatible with SkMatrix.
+    void transform(const float matrix[9]);
 
+#ifdef HAVE_ANDROID_OS
     status_t readFromParcel(Parcel* parcel);
     status_t writeToParcel(Parcel* parcel) const;
 #endif
diff --git a/include/input/KeycodeLabels.h b/include/input/KeycodeLabels.h
index c76ba12..c64c5d8 100644
--- a/include/input/KeycodeLabels.h
+++ b/include/input/KeycodeLabels.h
@@ -246,6 +246,7 @@
     { "ASSIST", 219 },
     { "BRIGHTNESS_DOWN", 220 },
     { "BRIGHTNESS_UP", 221 },
+    { "MEDIA_AUDIO_TRACK", 222 },
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 5a38b95..5951a3f 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -362,12 +362,12 @@
     return err;
 }
 
-int IPCThreadState::getCallingPid()
+int IPCThreadState::getCallingPid() const
 {
     return mCallingPid;
 }
 
-int IPCThreadState::getCallingUid()
+int IPCThreadState::getCallingUid() const
 {
     return mCallingUid;
 }
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 8d86c59..f5b2c7e 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -29,9 +29,9 @@
 
 namespace android {
 
-BufferItemConsumer::BufferItemConsumer(uint32_t consumerUsage,
-        int bufferCount, bool synchronousMode) :
-    ConsumerBase(new BufferQueue(true) )
+BufferItemConsumer::BufferItemConsumer(const sp<BufferQueue>& bq,
+        uint32_t consumerUsage, int bufferCount, bool synchronousMode) :
+    ConsumerBase(bq)
 {
     mBufferQueue->setConsumerUsageBits(consumerUsage);
     mBufferQueue->setSynchronousMode(synchronousMode);
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index 56bc7c6..adddfc2 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -30,8 +30,9 @@
 
 namespace android {
 
-CpuConsumer::CpuConsumer(uint32_t maxLockedBuffers, bool synchronousMode) :
-    ConsumerBase(new BufferQueue(true) ),
+CpuConsumer::CpuConsumer(const sp<BufferQueue>& bq,
+        uint32_t maxLockedBuffers, bool synchronousMode) :
+    ConsumerBase(bq),
     mMaxLockedBuffers(maxLockedBuffers),
     mCurrentLockedBuffers(0)
 {
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index d12083f..07f27c3 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -78,9 +78,9 @@
 static void mtxMul(float out[16], const float a[16], const float b[16]);
 
 
-GLConsumer::GLConsumer(GLuint tex, bool allowSynchronousMode,
-        GLenum texTarget, bool useFenceSync, const sp<BufferQueue> &bufferQueue) :
-    ConsumerBase(bufferQueue == 0 ? new BufferQueue(allowSynchronousMode) : bufferQueue),
+GLConsumer::GLConsumer(const sp<BufferQueue>& bq, GLuint tex,
+        GLenum texTarget, bool useFenceSync) :
+    ConsumerBase(bq),
     mCurrentTransform(0),
     mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
     mCurrentFence(Fence::NO_FENCE),
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index f345df8..94f21b6 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -633,7 +633,8 @@
 
 sp<CpuConsumer> ScreenshotClient::getCpuConsumer() const {
     if (mCpuConsumer == NULL) {
-        mCpuConsumer = new CpuConsumer(1);
+        sp<BufferQueue> bq = new BufferQueue();
+        mCpuConsumer = new CpuConsumer(bq, 1);
         mCpuConsumer->setName(String8("ScreenshotClient"));
     }
     return mCpuConsumer;
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 73fdd04..f8a35b4 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -66,7 +66,8 @@
                 test_info->name(),
                 params.width, params.height,
                 params.maxLockedBuffers, params.format);
-        mCC = new CpuConsumer(params.maxLockedBuffers);
+        sp<BufferQueue> bq = new BufferQueue();
+        mCC = new CpuConsumer(bq, params.maxLockedBuffers);
         String8 name("CpuConsumer_Under_Test");
         mCC->setName(name);
         mSTC = new Surface(mCC->getProducerInterface());
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index 7376b4c..46bcb22 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -40,7 +40,8 @@
         ALOGV("Begin test: %s.%s", testInfo->test_case_name(),
                 testInfo->name());
 
-        mST = new GLConsumer(123);
+        sp<BufferQueue> bq = new BufferQueue();
+        mST = new GLConsumer(bq, 123);
         mSTC = new Surface(mST->getBufferQueue());
         mANW = mSTC;
 
@@ -715,7 +716,8 @@
         ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
 
         for (int i = 0; i < NUM_SURFACE_TEXTURES; i++) {
-            sp<GLConsumer> st(new GLConsumer(i));
+            sp<BufferQueue> bq = new BufferQueue();
+            sp<GLConsumer> st(new GLConsumer(bq, i));
             sp<Surface> stc(new Surface(st->getBufferQueue()));
             mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig,
                     static_cast<ANativeWindow*>(stc.get()), NULL);
diff --git a/libs/gui/tests/SurfaceTexture_test.cpp b/libs/gui/tests/SurfaceTexture_test.cpp
index dd6c435..d97521a 100644
--- a/libs/gui/tests/SurfaceTexture_test.cpp
+++ b/libs/gui/tests/SurfaceTexture_test.cpp
@@ -385,7 +385,8 @@
 
     virtual void SetUp() {
         GLTest::SetUp();
-        mGlConsumer = new GLConsumer(TEX_ID);
+        sp<BufferQueue> bq = new BufferQueue();
+        mGlConsumer = new GLConsumer(bq, TEX_ID);
         mSurface = new Surface(mGlConsumer->getBufferQueue());
         mANW = mSurface.get();
 
@@ -479,7 +480,8 @@
 
     virtual void SetUp() {
         GLTest::SetUp();
-        mST = new GLConsumer(TEX_ID);
+        sp<BufferQueue> bq = new BufferQueue();
+        mST = new GLConsumer(bq, TEX_ID);
         mSTC = new Surface(mST->getBufferQueue());
         mANW = mSTC;
         mTextureRenderer = new TextureRenderer(TEX_ID, mST);
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 429becf..953f6f9 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -87,7 +87,8 @@
     sp<ANativeWindow> anw(mSurface);
 
     // Verify the screenshot works with no protected buffers.
-    sp<CpuConsumer> consumer = new CpuConsumer(1);
+    sp<BufferQueue> bq = new BufferQueue();
+    sp<CpuConsumer> consumer = new CpuConsumer(bq, 1);
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
     sp<IBinder> display(sf->getBuiltInDisplay(ISurfaceComposer::eDisplayIdMain));
     ASSERT_EQ(NO_ERROR, sf->captureScreen(display, consumer->getBufferQueue(),
diff --git a/libs/input/Android.mk b/libs/input/Android.mk
index 2a1e762..944ac7f 100644
--- a/libs/input/Android.mk
+++ b/libs/input/Android.mk
@@ -12,8 +12,6 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-ifneq ($(TARGET_BUILD_PDK),true)
-
 LOCAL_PATH:= $(call my-dir)
 
 # libinput is partially built for the host (used by build time keymap validation tool)
@@ -29,6 +27,7 @@
 
 deviceSources := \
     $(commonSources) \
+    IInputFlinger.cpp \
     InputTransport.cpp \
     VelocityControl.cpp \
     VelocityTracker.cpp
@@ -61,14 +60,7 @@
 	liblog \
 	libcutils \
 	libutils \
-	libbinder \
-	libskia \
-	libz
-
-LOCAL_C_INCLUDES := \
-    external/skia/include/core \
-    external/icu4c/common \
-	external/zlib
+	libbinder
 
 LOCAL_MODULE:= libinput
 
@@ -85,5 +77,3 @@
 ifeq (,$(ONE_SHOT_MAKEFILE))
 include $(call first-makefiles-under,$(LOCAL_PATH))
 endif
-
-endif #!PDK
diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp
new file mode 100644
index 0000000..e009731
--- /dev/null
+++ b/libs/input/IInputFlinger.cpp
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <binder/Parcel.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+
+#include <input/IInputFlinger.h>
+
+
+namespace android {
+
+class BpInputFlinger : public BpInterface<IInputFlinger> {
+public:
+    BpInputFlinger(const sp<IBinder>& impl) :
+            BpInterface<IInputFlinger>(impl) { }
+
+    virtual status_t doSomething() {
+        Parcel data, reply;
+        data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor());
+        remote()->transact(BnInputFlinger::DO_SOMETHING_TRANSACTION, data, &reply);
+        return reply.readInt32();
+    }
+};
+
+IMPLEMENT_META_INTERFACE(InputFlinger, "android.input.IInputFlinger");
+
+
+status_t BnInputFlinger::onTransact(
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+    switch(code) {
+    case DO_SOMETHING_TRANSACTION: {
+        CHECK_INTERFACE(IInputFlinger, data, reply);
+        reply->writeInt32(0);
+        break;
+    }
+    default:
+        return BBinder::onTransact(code, data, reply, flags);
+    }
+    return NO_ERROR;
+}
+
+};
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 7a217c3..6f53996 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -24,10 +24,6 @@
 
 #ifdef HAVE_ANDROID_OS
 #include <binder/Parcel.h>
-
-#include "SkPoint.h"
-#include "SkMatrix.h"
-#include "SkScalar.h"
 #endif
 
 namespace android {
@@ -74,6 +70,7 @@
         case AKEYCODE_MUTE:
         case AKEYCODE_BRIGHTNESS_DOWN:
         case AKEYCODE_BRIGHTNESS_UP:
+        case AKEYCODE_MEDIA_AUDIO_TRACK:
             return true;
     }
     
@@ -112,6 +109,7 @@
         case AKEYCODE_SEARCH:
         case AKEYCODE_BRIGHTNESS_DOWN:
         case AKEYCODE_BRIGHTNESS_UP:
+        case AKEYCODE_MEDIA_AUDIO_TRACK:
             return true;
     }
     
@@ -421,17 +419,30 @@
     }
 }
 
-#ifdef HAVE_ANDROID_OS
-static inline float transformAngle(const SkMatrix* matrix, float angleRadians) {
+static void transformPoint(const float matrix[9], float x, float y, float *outX, float *outY) {
+    // Apply perspective transform like Skia.
+    float newX = matrix[0] * x + matrix[1] * y + matrix[2];
+    float newY = matrix[3] * x + matrix[4] * y + matrix[5];
+    float newZ = matrix[6] * x + matrix[7] * y + matrix[8];
+    if (newZ) {
+        newZ = 1.0f / newZ;
+    }
+    *outX = newX * newZ;
+    *outY = newY * newZ;
+}
+
+static float transformAngle(const float matrix[9], float angleRadians,
+        float originX, float originY) {
     // Construct and transform a vector oriented at the specified clockwise angle from vertical.
     // Coordinate system: down is increasing Y, right is increasing X.
-    SkPoint vector;
-    vector.fX = SkFloatToScalar(sinf(angleRadians));
-    vector.fY = SkFloatToScalar(-cosf(angleRadians));
-    matrix->mapVectors(& vector, 1);
+    float x = sinf(angleRadians);
+    float y = -cosf(angleRadians);
+    transformPoint(matrix, x, y, &x, &y);
+    x -= originX;
+    y -= originY;
 
     // Derive the transformed vector's clockwise angle from vertical.
-    float result = atan2f(SkScalarToFloat(vector.fX), SkScalarToFloat(-vector.fY));
+    float result = atan2f(x, -y);
     if (result < - M_PI_2) {
         result += M_PI;
     } else if (result > M_PI_2) {
@@ -440,25 +451,24 @@
     return result;
 }
 
-void MotionEvent::transform(const SkMatrix* matrix) {
-    float oldXOffset = mXOffset;
-    float oldYOffset = mYOffset;
-
+void MotionEvent::transform(const float matrix[9]) {
     // The tricky part of this implementation is to preserve the value of
     // rawX and rawY.  So we apply the transformation to the first point
-    // then derive an appropriate new X/Y offset that will preserve rawX and rawY.
-    SkPoint point;
+    // then derive an appropriate new X/Y offset that will preserve rawX
+     // and rawY for that point.
+    float oldXOffset = mXOffset;
+    float oldYOffset = mYOffset;
+    float newX, newY;
     float rawX = getRawX(0);
     float rawY = getRawY(0);
-    matrix->mapXY(SkFloatToScalar(rawX + oldXOffset), SkFloatToScalar(rawY + oldYOffset),
-            & point);
-    float newX = SkScalarToFloat(point.fX);
-    float newY = SkScalarToFloat(point.fY);
-    float newXOffset = newX - rawX;
-    float newYOffset = newY - rawY;
+    transformPoint(matrix, rawX + oldXOffset, rawY + oldYOffset, &newX, &newY);
+    mXOffset = newX - rawX;
+    mYOffset = newY - rawY;
 
-    mXOffset = newXOffset;
-    mYOffset = newYOffset;
+    // Determine how the origin is transformed by the matrix so that we
+    // can transform orientation vectors.
+    float originX, originY;
+    transformPoint(matrix, 0, 0, &originX, &originY);
 
     // Apply the transformation to all samples.
     size_t numSamples = mSamplePointerCoords.size();
@@ -466,15 +476,17 @@
         PointerCoords& c = mSamplePointerCoords.editItemAt(i);
         float x = c.getAxisValue(AMOTION_EVENT_AXIS_X) + oldXOffset;
         float y = c.getAxisValue(AMOTION_EVENT_AXIS_Y) + oldYOffset;
-        matrix->mapXY(SkFloatToScalar(x), SkFloatToScalar(y), &point);
-        c.setAxisValue(AMOTION_EVENT_AXIS_X, SkScalarToFloat(point.fX) - newXOffset);
-        c.setAxisValue(AMOTION_EVENT_AXIS_Y, SkScalarToFloat(point.fY) - newYOffset);
+        transformPoint(matrix, x, y, &x, &y);
+        c.setAxisValue(AMOTION_EVENT_AXIS_X, x - mXOffset);
+        c.setAxisValue(AMOTION_EVENT_AXIS_Y, y - mYOffset);
 
         float orientation = c.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION);
-        c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, transformAngle(matrix, orientation));
+        c.setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION,
+                transformAngle(matrix, orientation, originX, originY));
     }
 }
 
+#ifdef HAVE_ANDROID_OS
 status_t MotionEvent::readFromParcel(Parcel* parcel) {
     size_t pointerCount = parcel->readInt32();
     size_t sampleCount = parcel->readInt32();
diff --git a/libs/input/tests/Android.mk b/libs/input/tests/Android.mk
index 4292741..c62dff1 100644
--- a/libs/input/tests/Android.mk
+++ b/libs/input/tests/Android.mk
@@ -14,8 +14,7 @@
     libutils \
     libbinder \
     libui \
-    libstlport \
-    libskia
+    libstlport
 
 static_libraries := \
     libgtest \
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index ab1feb3..78ea98e 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -17,7 +17,6 @@
 #include <math.h>
 
 #include <binder/Parcel.h>
-#include <core/SkMatrix.h>
 #include <gtest/gtest.h>
 #include <input/Input.h>
 
@@ -519,6 +518,20 @@
     ASSERT_NO_FATAL_FAILURE(assertEqualsEventWithHistory(&outEvent));
 }
 
+static void setRotationMatrix(float matrix[9], float angle) {
+    float sin = sinf(angle);
+    float cos = cosf(angle);
+    matrix[0] = cos;
+    matrix[1] = -sin;
+    matrix[2] = 0;
+    matrix[3] = sin;
+    matrix[4] = cos;
+    matrix[5] = 0;
+    matrix[6] = 0;
+    matrix[7] = 0;
+    matrix[8] = 1.0f;
+}
+
 TEST_F(MotionEventTest, Transform) {
     // Generate some points on a circle.
     // Each point 'i' is a point on a circle of radius ROTATION centered at (3,2) at an angle
@@ -561,9 +574,9 @@
     ASSERT_NEAR(originalRawY, event.getRawY(0), 0.001);
 
     // Apply a rotation about the origin by ROTATION degrees clockwise.
-    SkMatrix matrix;
-    matrix.setRotate(ROTATION);
-    event.transform(&matrix);
+    float matrix[9];
+    setRotationMatrix(matrix, ROTATION * PI_180);
+    event.transform(matrix);
 
     // Check the points.
     for (size_t i = 0; i < pointerCount; i++) {
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 015740a..6c285d3 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -373,7 +373,7 @@
         if (native_window_api_connect(window, NATIVE_WINDOW_API_EGL) != OK) {
             ALOGE("EGLNativeWindowType %p already connected to another API",
                     window);
-            return setError(EGL_BAD_NATIVE_WINDOW, EGL_NO_SURFACE);
+            return setError(EGL_BAD_ALLOC, EGL_NO_SURFACE);
         }
 
         // set the native window's buffers format to match this config
diff --git a/services/inputflinger/Android.mk b/services/inputflinger/Android.mk
new file mode 100644
index 0000000..7148db8
--- /dev/null
+++ b/services/inputflinger/Android.mk
@@ -0,0 +1,35 @@
+# Copyright (C) 2013 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    InputFlinger.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    libcutils \
+    libinput \
+    liblog \
+    libutils
+
+LOCAL_CFLAGS += -fvisibility=hidden
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+LOCAL_MODULE := libinputflinger
+
+include $(BUILD_SHARED_LIBRARY)
+
diff --git a/services/inputflinger/InputFlinger.cpp b/services/inputflinger/InputFlinger.cpp
new file mode 100644
index 0000000..9ea6ce5
--- /dev/null
+++ b/services/inputflinger/InputFlinger.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2013 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 "InputFlinger"
+
+#include "InputFlinger.h"
+
+#include <stdint.h>
+#include <unistd.h>
+
+#include <sys/types.h>
+
+#include <binder/IPCThreadState.h>
+#include <binder/PermissionCache.h>
+#include <cutils/log.h>
+#include <private/android_filesystem_config.h>
+
+namespace android {
+
+const String16 sAccessInputFlingerPermission("android.permission.ACCESS_INPUT_FLINGER");
+const String16 sDumpPermission("android.permission.DUMP");
+
+
+InputFlinger::InputFlinger() :
+        BnInputFlinger() {
+    ALOGI("InputFlinger is starting");
+}
+
+InputFlinger::~InputFlinger() {
+}
+
+status_t InputFlinger::onTransact(
+        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+    switch (code) {
+    case DO_SOMETHING_TRANSACTION:
+        const IPCThreadState* ipc = IPCThreadState::self();
+        const int pid = ipc->getCallingPid();
+        const int uid = ipc->getCallingUid();
+        if (!PermissionCache::checkPermission(sAccessInputFlingerPermission, pid, uid)) {
+            ALOGE("Permission Denial: "
+                    "can't access InputFlinger from pid=%d, uid=%d", pid, uid);
+            return PERMISSION_DENIED;
+        }
+        break;
+    }
+
+    return BnInputFlinger::onTransact(code, data, reply, flags);
+}
+
+status_t InputFlinger::dump(int fd, const Vector<String16>& args) {
+    String8 result;
+    const IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+    if ((uid != AID_SHELL)
+            && !PermissionCache::checkPermission(sDumpPermission, pid, uid)) {
+        result.appendFormat("Permission Denial: "
+                "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid);
+    } else {
+        dumpInternal(result);
+    }
+    write(fd, result.string(), result.size());
+    return OK;
+}
+
+void InputFlinger::dumpInternal(String8& result) {
+    result.append("INPUT FLINGER (dumpsys inputflinger)\n");
+    result.append("... nothing here yet...\n");
+}
+
+status_t InputFlinger::doSomething() {
+    ALOGI("Did something...");
+    return OK;
+}
+
+}; // namespace android
diff --git a/services/inputflinger/InputFlinger.h b/services/inputflinger/InputFlinger.h
new file mode 100644
index 0000000..731ab17
--- /dev/null
+++ b/services/inputflinger/InputFlinger.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_INPUT_FLINGER_H
+#define ANDROID_INPUT_FLINGER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <cutils/compiler.h>
+#include <input/IInputFlinger.h>
+#include <utils/String8.h>
+#include <utils/String16.h>
+
+namespace android {
+
+class InputFlinger : public BnInputFlinger {
+public:
+    static char const* getServiceName() ANDROID_API {
+        return "inputflinger";
+    }
+
+    InputFlinger() ANDROID_API;
+
+    // IBinder interface
+    virtual status_t onTransact(uint32_t code,
+            const Parcel& data, Parcel* reply, uint32_t flags);
+    virtual status_t dump(int fd, const Vector<String16>& args);
+
+    // IInputFlinger interface
+    virtual status_t doSomething();
+
+private:
+    virtual ~InputFlinger();
+
+    void dumpInternal(String8& result);
+};
+
+} // namespace android
+
+#endif // ANDROID_INPUT_FLINGER_H
diff --git a/services/sensorservice/BatteryService.cpp b/services/sensorservice/BatteryService.cpp
index 70b65ab..38dc749 100644
--- a/services/sensorservice/BatteryService.cpp
+++ b/services/sensorservice/BatteryService.cpp
@@ -33,7 +33,7 @@
 BatteryService::BatteryService() {
     const sp<IServiceManager> sm(defaultServiceManager());
     if (sm != NULL) {
-        const String16 name("batteryinfo");
+        const String16 name("batterystats");
         mBatteryStatService = sm->getService(name);
     }
 }
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 18a1523..2fa5dbd 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -107,13 +107,10 @@
     return c;
 }
 
-status_t SensorDevice::resetStateWithoutActuatingHardware(void *ident, int handle)
-{
-    if (!mSensorDevice) return NO_INIT;
-    Info& info( mActivationCount.editValueFor(handle));
+void SensorDevice::autoDisable(void *ident, int handle) {
+    Info& info( mActivationCount.editValueFor(handle) );
     Mutex::Autolock _l(mLock);
     info.rates.removeItem(ident);
-    return NO_ERROR;
 }
 
 status_t SensorDevice::activate(void* ident, int handle, int enabled)
@@ -164,6 +161,15 @@
         ALOGE_IF(err, "Error %s sensor %d (%s)",
                 enabled ? "activating" : "disabling",
                 handle, strerror(-err));
+
+        if (err != NO_ERROR) {
+            // clean-up on failure
+            if (enabled) {
+                // failure when enabling the sensor
+                Mutex::Autolock _l(mLock);
+                info.rates.removeItem(ident);
+            }
+        }
     }
 
     { // scope for the lock
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index ca67ce2..b50e205 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -56,7 +56,7 @@
     ssize_t poll(sensors_event_t* buffer, size_t count);
     status_t activate(void* ident, int handle, int enabled);
     status_t setDelay(void* ident, int handle, int64_t ns);
-    status_t resetStateWithoutActuatingHardware(void *ident, int handle);
+    void autoDisable(void *ident, int handle);
     void dump(String8& result);
 };
 
diff --git a/services/sensorservice/SensorInterface.cpp b/services/sensorservice/SensorInterface.cpp
index cf0a11d..b483b75 100644
--- a/services/sensorservice/SensorInterface.cpp
+++ b/services/sensorservice/SensorInterface.cpp
@@ -54,8 +54,8 @@
     return mSensorDevice.setDelay(ident, handle, ns);
 }
 
-status_t HardwareSensor::resetStateWithoutActuatingHardware(void *ident, int handle) {
-    return mSensorDevice.resetStateWithoutActuatingHardware(ident, handle);
+void HardwareSensor::autoDisable(void *ident, int handle) {
+    mSensorDevice.autoDisable(ident, handle);
 }
 
 Sensor HardwareSensor::getSensor() const {
diff --git a/services/sensorservice/SensorInterface.h b/services/sensorservice/SensorInterface.h
index 2e709ae..2e14e57 100644
--- a/services/sensorservice/SensorInterface.h
+++ b/services/sensorservice/SensorInterface.h
@@ -40,11 +40,7 @@
     virtual status_t setDelay(void* ident, int handle, int64_t ns) = 0;
     virtual Sensor getSensor() const = 0;
     virtual bool isVirtual() const = 0;
-    virtual status_t resetStateWithoutActuatingHardware(void *ident, int handle) {
-        // Override when you want to clean up for sensors which auto disable
-        // after trigger, or when enabling sensors fail.
-        return INVALID_OPERATION;
-    }
+    virtual void autoDisable(void *ident, int handle) { }
 };
 
 // ---------------------------------------------------------------------------
@@ -66,7 +62,7 @@
     virtual status_t setDelay(void* ident, int handle, int64_t ns);
     virtual Sensor getSensor() const;
     virtual bool isVirtual() const { return false; }
-    virtual status_t resetStateWithoutActuatingHardware(void *ident, int handle);
+    virtual void autoDisable(void *ident, int handle);
 };
 
 
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 99993ba..e3d2a60 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -274,10 +274,8 @@
         if (type == SENSOR_TYPE_SIGNIFICANT_MOTION) {
             if (connection->hasSensor(handle)) {
                 sensor = mSensorMap.valueFor(handle);
-                err = sensor ?sensor->resetStateWithoutActuatingHardware(connection.get(), handle)
-                        : status_t(BAD_VALUE);
-                if (err != NO_ERROR) {
-                    ALOGE("Sensor Inteface: Resetting state failed with err: %d", err);
+                if (sensor != NULL) {
+                    sensor->autoDisable(connection.get(), handle);
                 }
                 cleanupWithoutDisable(connection, handle);
             }
@@ -509,8 +507,12 @@
     if (mInitCheck != NO_ERROR)
         return mInitCheck;
 
-    Mutex::Autolock _l(mLock);
     SensorInterface* sensor = mSensorMap.valueFor(handle);
+    if (sensor == NULL) {
+        return BAD_VALUE;
+    }
+
+    Mutex::Autolock _l(mLock);
     SensorRecord* rec = mActiveSensors.valueFor(handle);
     if (rec == 0) {
         rec = new SensorRecord(connection);
@@ -546,16 +548,11 @@
             handle, connection.get());
     }
 
-
     // we are setup, now enable the sensor.
-    status_t err = sensor ? sensor->activate(connection.get(), true) : status_t(BAD_VALUE);
-
+    status_t err = sensor->activate(connection.get(), true);
     if (err != NO_ERROR) {
-        // enable has failed, reset state in SensorDevice.
-        status_t resetErr = sensor ? sensor->resetStateWithoutActuatingHardware(connection.get(),
-                handle) : status_t(BAD_VALUE);
         // enable has failed, reset our state.
-        cleanupWithoutDisable(connection, handle);
+        cleanupWithoutDisableLocked(connection, handle);
     }
     return err;
 }
@@ -566,7 +563,8 @@
     if (mInitCheck != NO_ERROR)
         return mInitCheck;
 
-    status_t err = cleanupWithoutDisable(connection, handle);
+    Mutex::Autolock _l(mLock);
+    status_t err = cleanupWithoutDisableLocked(connection, handle);
     if (err == NO_ERROR) {
         SensorInterface* sensor = mSensorMap.valueFor(handle);
         err = sensor ? sensor->activate(connection.get(), false) : status_t(BAD_VALUE);
@@ -574,9 +572,14 @@
     return err;
 }
 
-status_t SensorService::cleanupWithoutDisable(const sp<SensorEventConnection>& connection,
-        int handle) {
+status_t SensorService::cleanupWithoutDisable(
+        const sp<SensorEventConnection>& connection, int handle) {
     Mutex::Autolock _l(mLock);
+    return cleanupWithoutDisableLocked(connection, handle);
+}
+
+status_t SensorService::cleanupWithoutDisableLocked(
+        const sp<SensorEventConnection>& connection, int handle) {
     SensorRecord* rec = mActiveSensors.valueFor(handle);
     if (rec) {
         // see if this connection becomes inactive
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 56b0a3e..69e5dbb 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -115,8 +115,10 @@
     static void sortEventBuffer(sensors_event_t* buffer, size_t count);
     Sensor registerSensor(SensorInterface* sensor);
     Sensor registerVirtualSensor(SensorInterface* sensor);
-    status_t cleanupWithoutDisable(const sp<SensorEventConnection>& connection,
-            int handle);
+    status_t cleanupWithoutDisable(
+            const sp<SensorEventConnection>& connection, int handle);
+    status_t cleanupWithoutDisableLocked(
+            const sp<SensorEventConnection>& connection, int handle);
     void cleanupAutoDisabledSensor(const sp<SensorEventConnection>& connection,
             sensors_event_t const* buffer, const int count);
 
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 2eae9c2..c67f4d8 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -188,6 +188,25 @@
     mPageFlipCount++;
 }
 
+status_t DisplayDevice::prepareFrame(const HWComposer& hwc) const {
+    DisplaySurface::CompositionType compositionType;
+    bool haveGles = hwc.hasGlesComposition(mHwcDisplayId);
+    bool haveHwc = hwc.hasHwcComposition(mHwcDisplayId);
+    if (haveGles && haveHwc) {
+        compositionType = DisplaySurface::COMPOSITION_MIXED;
+    } else if (haveGles) {
+        compositionType = DisplaySurface::COMPOSITION_GLES;
+    } else if (haveHwc) {
+        compositionType = DisplaySurface::COMPOSITION_HWC;
+    } else {
+        // Nothing to do -- when turning the screen off we get a frame like
+        // this. Call it a HWC frame since we won't be doing any GLES work but
+        // will do a prepare/set cycle.
+        compositionType = DisplaySurface::COMPOSITION_HWC;
+    }
+    return mDisplaySurface->prepareFrame(compositionType);
+}
+
 void DisplayDevice::swapBuffers(HWComposer& hwc) const {
     // We need to call eglSwapBuffers() unless:
     // (a) there was no GLES composition this frame, or
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index eefc107..748be1a 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -119,6 +119,8 @@
     int32_t                 getHwcDisplayId() const { return mHwcDisplayId; }
     const wp<IBinder>&      getDisplayToken() const { return mDisplayToken; }
 
+    status_t prepareFrame(const HWComposer& hwc) const;
+
     void swapBuffers(HWComposer& hwc) const;
     status_t compositionComplete() const;
 
diff --git a/services/surfaceflinger/DisplayHardware/DisplaySurface.h b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
index 2eca3cb..b0f460d 100644
--- a/services/surfaceflinger/DisplayHardware/DisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/DisplaySurface.h
@@ -32,6 +32,18 @@
 public:
     virtual sp<IGraphicBufferProducer> getIGraphicBufferProducer() const = 0;
 
+    // prepareFrame is called after the composition configuration is known but
+    // before composition takes place. The DisplaySurface can use the
+    // composition type to decide how to manage the flow of buffers between
+    // GLES and HWC for this frame.
+    enum CompositionType {
+        COMPOSITION_UNKNOWN = 0,
+        COMPOSITION_GLES    = 1,
+        COMPOSITION_HWC     = 2,
+        COMPOSITION_MIXED   = COMPOSITION_GLES | COMPOSITION_HWC
+    };
+    virtual status_t prepareFrame(CompositionType compositionType) = 0;
+
     // Should be called when composition rendering is complete for a frame (but
     // eglSwapBuffers hasn't necessarily been called). Required by certain
     // older drivers for synchronization.
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 938459e..7987da3 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -72,6 +72,10 @@
     return getBufferQueue();
 }
 
+status_t FramebufferSurface::prepareFrame(CompositionType compositionType) {
+    return NO_ERROR;
+}
+
 status_t FramebufferSurface::advanceFrame() {
     // Once we remove FB HAL support, we can call nextBuffer() from here
     // instead of using onFrameAvailable(). No real benefit, except it'll be
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
index c86e9ae..92a7f9b 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.h
@@ -41,6 +41,7 @@
 
     virtual sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
 
+    virtual status_t prepareFrame(CompositionType compositionType);
     virtual status_t compositionComplete();
     virtual status_t advanceFrame();
     virtual void onFrameCommitted();
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 1cdabc4..f6256f9 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -16,9 +16,6 @@
 
 #define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-// Uncomment this to remove support for HWC_DEVICE_API_VERSION_0_3 and older
-#define HWC_REMOVE_DEPRECATED_VERSIONS 1
-
 #include <stdint.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -51,9 +48,9 @@
 
 namespace android {
 
-// This is not a real HWC version. It's used for in-development features that
-// haven't been committed to a specific real HWC version.
-#define HWC_DEVICE_API_VERSION_1_EXP HARDWARE_DEVICE_API_VERSION_2(1, 0xFF, HWC_HEADER_VERSION)
+#ifndef HWC_DEVICE_API_VERSION_1_3
+#define HWC_DEVICE_API_VERSION_1_3 HARDWARE_DEVICE_API_VERSION_2(1, 3, HWC_HEADER_VERSION)
+#endif
 
 #define MIN_HWC_HEADER_VERSION HWC_HEADER_VERSION
 
@@ -157,8 +154,8 @@
 
         // the number of displays we actually have depends on the
         // hw composer version
-        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_EXP)) {
-            // 1.?? adds support for virtual displays
+        if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
+            // 1.3 adds support for virtual displays
             mNumDisplays = MAX_DISPLAYS;
         } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
             // 1.1 adds support for multiple displays
@@ -583,7 +580,7 @@
         }
         mLists[i] = disp.list;
         if (mLists[i]) {
-            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_EXP)) {
+            if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_3)) {
                 mLists[i]->outbuf = NULL;
                 mLists[i]->outbufAcquireFenceFd = -1;
             } else if (hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1)) {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 2838b23..a324e94 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -14,27 +14,89 @@
  * limitations under the License.
  */
 
+// #define LOG_NDEBUG 0
 #include "VirtualDisplaySurface.h"
-
-#include <cutils/log.h>
-#include <gui/IGraphicBufferProducer.h>
+#include "HWComposer.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
 // ---------------------------------------------------------------------------
 
+#define VDS_LOGE(msg, ...) ALOGE("[%s] "msg, \
+        mDisplayName.string(), ##__VA_ARGS__)
+#define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] "msg, \
+        mDisplayName.string(), ##__VA_ARGS__)
+#define VDS_LOGV(msg, ...) ALOGV("[%s] "msg, \
+        mDisplayName.string(), ##__VA_ARGS__)
+
+static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) {
+    switch (type) {
+        case DisplaySurface::COMPOSITION_UNKNOWN: return "UNKNOWN";
+        case DisplaySurface::COMPOSITION_GLES:    return "GLES";
+        case DisplaySurface::COMPOSITION_HWC:     return "HWC";
+        case DisplaySurface::COMPOSITION_MIXED:   return "MIXED";
+        default:                                  return "<INVALID>";
+    }
+}
+
 VirtualDisplaySurface::VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
         const sp<IGraphicBufferProducer>& sink, const String8& name)
-:   mSink(sink)
+:   ConsumerBase(new BufferQueue(true)),
+    mHwc(hwc),
+    mDisplayId(dispId),
+    mDisplayName(name),
+    mProducerUsage(GRALLOC_USAGE_HW_COMPOSER),
+    mProducerSlotSource(0),
+    mDbgState(DBG_STATE_IDLE),
+    mDbgLastCompositionType(COMPOSITION_UNKNOWN)
 {
-    LOG_ALWAYS_FATAL_IF(dispId >= 0);
+    mSource[SOURCE_SINK] = sink;
+    mSource[SOURCE_SCRATCH] = mBufferQueue;
+
+    resetPerFrameState();
+
+    int sinkWidth, sinkHeight;
+    mSource[SOURCE_SINK]->query(NATIVE_WINDOW_WIDTH, &sinkWidth);
+    mSource[SOURCE_SINK]->query(NATIVE_WINDOW_HEIGHT, &sinkHeight);
+
+    ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.string());
+    mBufferQueue->setConsumerName(ConsumerBase::mName);
+    mBufferQueue->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
+    mBufferQueue->setDefaultBufferSize(sinkWidth, sinkHeight);
+    mBufferQueue->setDefaultMaxBufferCount(2);
 }
 
 VirtualDisplaySurface::~VirtualDisplaySurface() {
 }
 
 sp<IGraphicBufferProducer> VirtualDisplaySurface::getIGraphicBufferProducer() const {
-    return mSink;
+    if (mDisplayId >= 0) {
+        return static_cast<IGraphicBufferProducer*>(
+                const_cast<VirtualDisplaySurface*>(this));
+    } else {
+        // There won't be any interaction with HWC for this virtual display,
+        // so the GLES driver can pass buffers directly to the sink.
+        return mSource[SOURCE_SINK];
+    }
+}
+
+status_t VirtualDisplaySurface::prepareFrame(CompositionType compositionType) {
+    if (mDisplayId < 0)
+        return NO_ERROR;
+
+    VDS_LOGW_IF(mDbgState != DBG_STATE_IDLE,
+            "Unexpected prepareFrame() in %s state", dbgStateStr());
+    mDbgState = DBG_STATE_PREPARED;
+
+    mCompositionType = compositionType;
+
+    if (mCompositionType != mDbgLastCompositionType) {
+        VDS_LOGV("prepareFrame: composition type changed to %s",
+                dbgCompositionTypeStr(mCompositionType));
+        mDbgLastCompositionType = mCompositionType;
+    }
+
+    return NO_ERROR;
 }
 
 status_t VirtualDisplaySurface::compositionComplete() {
@@ -42,15 +104,319 @@
 }
 
 status_t VirtualDisplaySurface::advanceFrame() {
-    return NO_ERROR;
+    if (mDisplayId < 0)
+        return NO_ERROR;
+
+    if (mCompositionType == COMPOSITION_HWC) {
+        VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
+                "Unexpected advanceFrame() in %s state on HWC frame",
+                dbgStateStr());
+    } else {
+        VDS_LOGW_IF(mDbgState != DBG_STATE_GLES_DONE,
+                "Unexpected advanceFrame() in %s state on GLES/MIXED frame",
+                dbgStateStr());
+    }
+    mDbgState = DBG_STATE_HWC;
+
+    status_t result;
+    sp<Fence> outFence;
+    if (mCompositionType != COMPOSITION_GLES) {
+        // Dequeue an output buffer from the sink
+        uint32_t transformHint, numPendingBuffers;
+        mQueueBufferOutput.deflate(&mSinkBufferWidth, &mSinkBufferHeight,
+                &transformHint, &numPendingBuffers);
+        int sslot;
+        result = dequeueBuffer(SOURCE_SINK, 0, &sslot, &outFence);
+        if (result < 0)
+            return result;
+        mOutputProducerSlot = mapSource2ProducerSlot(SOURCE_SINK, sslot);
+    }
+
+    if (mCompositionType == COMPOSITION_HWC) {
+        // We just dequeued the output buffer, use it for FB as well
+        mFbProducerSlot = mOutputProducerSlot;
+        mFbFence = outFence;
+    } else if (mCompositionType == COMPOSITION_GLES) {
+        mOutputProducerSlot = mFbProducerSlot;
+        outFence = mFbFence;
+    } else {
+        // mFbFence and mFbProducerSlot were set in queueBuffer,
+        // and mOutputProducerSlot and outFence were set above when dequeueing
+        // the sink buffer.
+    }
+
+    if (mFbProducerSlot < 0 || mOutputProducerSlot < 0) {
+        // Last chance bailout if something bad happened earlier. For example,
+        // in a GLES configuration, if the sink disappears then dequeueBuffer
+        // will fail, the GLES driver won't queue a buffer, but SurfaceFlinger
+        // will soldier on. So we end up here without a buffer. There should
+        // be lots of scary messages in the log just before this.
+        VDS_LOGE("advanceFrame: no buffer, bailing out");
+        return NO_MEMORY;
+    }
+
+    sp<GraphicBuffer> fbBuffer = mProducerBuffers[mFbProducerSlot];
+    sp<GraphicBuffer> outBuffer = mProducerBuffers[mOutputProducerSlot];
+    VDS_LOGV("advanceFrame: fb=%d(%p) out=%d(%p)",
+            mFbProducerSlot, fbBuffer.get(),
+            mOutputProducerSlot, outBuffer.get());
+
+    result = mHwc.fbPost(mDisplayId, mFbFence, fbBuffer);
+    if (result == NO_ERROR) {
+        result = mHwc.setOutputBuffer(mDisplayId, outFence, outBuffer);
+    }
+
+    return result;
 }
 
 void VirtualDisplaySurface::onFrameCommitted() {
+    if (mDisplayId < 0)
+        return;
+
+    VDS_LOGW_IF(mDbgState != DBG_STATE_HWC,
+            "Unexpected onFrameCommitted() in %s state", dbgStateStr());
+    mDbgState = DBG_STATE_IDLE;
+
+    sp<Fence> fbFence = mHwc.getAndResetReleaseFence(mDisplayId);
+    if (mCompositionType == COMPOSITION_MIXED && mFbProducerSlot >= 0) {
+        // release the scratch buffer back to the pool
+        Mutex::Autolock lock(mMutex);
+        int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, mFbProducerSlot);
+        VDS_LOGV("onFrameCommitted: release scratch sslot=%d", sslot);
+        addReleaseFenceLocked(sslot, mProducerBuffers[mFbProducerSlot], fbFence);
+        releaseBufferLocked(sslot, mProducerBuffers[mFbProducerSlot],
+                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
+    }
+
+    if (mOutputProducerSlot >= 0) {
+        int sslot = mapProducer2SourceSlot(SOURCE_SINK, mOutputProducerSlot);
+        QueueBufferOutput qbo;
+        sp<Fence> outFence = mHwc.getLastRetireFence(mDisplayId);
+        VDS_LOGV("onFrameCommitted: queue sink sslot=%d", sslot);
+        status_t result = mSource[SOURCE_SINK]->queueBuffer(sslot,
+                QueueBufferInput(systemTime(),
+                    Rect(mSinkBufferWidth, mSinkBufferHeight),
+                    NATIVE_WINDOW_SCALING_MODE_FREEZE, 0, outFence),
+                &qbo);
+        if (result == NO_ERROR) {
+            updateQueueBufferOutput(qbo);
+        }
+    }
+
+    resetPerFrameState();
 }
 
 void VirtualDisplaySurface::dump(String8& result) const {
 }
 
+status_t VirtualDisplaySurface::requestBuffer(int pslot,
+        sp<GraphicBuffer>* outBuf) {
+    VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
+            "Unexpected requestBuffer pslot=%d in %s state",
+            pslot, dbgStateStr());
+
+    *outBuf = mProducerBuffers[pslot];
+    return NO_ERROR;
+}
+
+status_t VirtualDisplaySurface::setBufferCount(int bufferCount) {
+    return mSource[SOURCE_SINK]->setBufferCount(bufferCount);
+}
+
+status_t VirtualDisplaySurface::dequeueBuffer(Source source,
+        uint32_t format, int* sslot, sp<Fence>* fence) {
+    status_t result = mSource[source]->dequeueBuffer(sslot, fence,
+            mSinkBufferWidth, mSinkBufferHeight, format, mProducerUsage);
+    if (result < 0)
+        return result;
+    int pslot = mapSource2ProducerSlot(source, *sslot);
+    VDS_LOGV("dequeueBuffer(%s): sslot=%d pslot=%d result=%d",
+            dbgSourceStr(source), *sslot, pslot, result);
+    uint32_t sourceBit = static_cast<uint32_t>(source) << pslot;
+
+    if ((mProducerSlotSource & (1u << pslot)) != sourceBit) {
+        // This slot was previously dequeued from the other source; must
+        // re-request the buffer.
+        result |= BUFFER_NEEDS_REALLOCATION;
+        mProducerSlotSource &= ~(1u << pslot);
+        mProducerSlotSource |= sourceBit;
+    }
+
+    if (result & RELEASE_ALL_BUFFERS) {
+        for (uint32_t i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
+            if ((mProducerSlotSource & (1u << i)) == sourceBit)
+                mProducerBuffers[i].clear();
+        }
+    }
+    if (result & BUFFER_NEEDS_REALLOCATION) {
+        mSource[source]->requestBuffer(*sslot, &mProducerBuffers[pslot]);
+        VDS_LOGV("dequeueBuffer(%s): buffers[%d]=%p",
+                dbgSourceStr(source), pslot, mProducerBuffers[pslot].get());
+    }
+
+    return result;
+}
+
+status_t VirtualDisplaySurface::dequeueBuffer(int* pslot, sp<Fence>* fence,
+        uint32_t w, uint32_t h, uint32_t format, uint32_t usage) {
+    VDS_LOGW_IF(mDbgState != DBG_STATE_PREPARED,
+            "Unexpected dequeueBuffer() in %s state", dbgStateStr());
+    mDbgState = DBG_STATE_GLES;
+
+    VDS_LOGV("dequeueBuffer %dx%d fmt=%d usage=%#x", w, h, format, usage);
+
+    mProducerUsage = usage | GRALLOC_USAGE_HW_COMPOSER;
+    Source source = fbSourceForCompositionType(mCompositionType);
+    if (source == SOURCE_SINK) {
+        mSinkBufferWidth = w;
+        mSinkBufferHeight = h;
+    }
+
+    int sslot;
+    status_t result = dequeueBuffer(source, format, &sslot, fence);
+    if (result >= 0) {
+        *pslot = mapSource2ProducerSlot(source, sslot);
+    }
+    return result;
+}
+
+status_t VirtualDisplaySurface::queueBuffer(int pslot,
+        const QueueBufferInput& input, QueueBufferOutput* output) {
+    VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
+            "Unexpected queueBuffer(pslot=%d) in %s state", pslot,
+            dbgStateStr());
+    mDbgState = DBG_STATE_GLES_DONE;
+
+    VDS_LOGV("queueBuffer pslot=%d", pslot);
+
+    status_t result;
+    if (mCompositionType == COMPOSITION_MIXED) {
+        // Queue the buffer back into the scratch pool
+        QueueBufferOutput scratchQBO;
+        int sslot = mapProducer2SourceSlot(SOURCE_SCRATCH, pslot);
+        result = mBufferQueue->queueBuffer(sslot, input, &scratchQBO);
+        if (result != NO_ERROR)
+            return result;
+
+        // Now acquire the buffer from the scratch pool -- should be the same
+        // slot and fence as we just queued.
+        Mutex::Autolock lock(mMutex);
+        BufferQueue::BufferItem item;
+        result = acquireBufferLocked(&item, 0);
+        if (result != NO_ERROR)
+            return result;
+        VDS_LOGW_IF(item.mBuf != sslot,
+                "queueBuffer: acquired sslot %d from SCRATCH after queueing sslot %d",
+                item.mBuf, sslot);
+        mFbProducerSlot = mapSource2ProducerSlot(SOURCE_SCRATCH, item.mBuf);
+        mFbFence = mSlots[item.mBuf].mFence;
+
+    } else {
+        LOG_FATAL_IF(mCompositionType != COMPOSITION_GLES,
+                "Unexpected queueBuffer in state %s for compositionType %s",
+                dbgStateStr(), dbgCompositionTypeStr(mCompositionType));
+
+        // Extract the GLES release fence for HWC to acquire
+        int64_t timestamp;
+        Rect crop;
+        int scalingMode;
+        uint32_t transform;
+        input.deflate(&timestamp, &crop, &scalingMode, &transform,
+                &mFbFence);
+
+        mFbProducerSlot = pslot;
+    }
+
+    *output = mQueueBufferOutput;
+    return NO_ERROR;
+}
+
+void VirtualDisplaySurface::cancelBuffer(int pslot, const sp<Fence>& fence) {
+    VDS_LOGW_IF(mDbgState != DBG_STATE_GLES,
+            "Unexpected cancelBuffer(pslot=%d) in %s state", pslot,
+            dbgStateStr());
+    VDS_LOGV("cancelBuffer pslot=%d", pslot);
+    Source source = fbSourceForCompositionType(mCompositionType);
+    return mSource[source]->cancelBuffer(
+            mapProducer2SourceSlot(source, pslot), fence);
+}
+
+int VirtualDisplaySurface::query(int what, int* value) {
+    return mSource[SOURCE_SINK]->query(what, value);
+}
+
+status_t VirtualDisplaySurface::setSynchronousMode(bool enabled) {
+    return mSource[SOURCE_SINK]->setSynchronousMode(enabled);
+}
+
+status_t VirtualDisplaySurface::connect(int api, QueueBufferOutput* output) {
+    QueueBufferOutput qbo;
+    status_t result = mSource[SOURCE_SINK]->connect(api, &qbo);
+    if (result == NO_ERROR) {
+        updateQueueBufferOutput(qbo);
+        *output = mQueueBufferOutput;
+    }
+    return result;
+}
+
+status_t VirtualDisplaySurface::disconnect(int api) {
+    return mSource[SOURCE_SINK]->disconnect(api);
+}
+
+void VirtualDisplaySurface::updateQueueBufferOutput(
+        const QueueBufferOutput& qbo) {
+    uint32_t w, h, transformHint, numPendingBuffers;
+    qbo.deflate(&w, &h, &transformHint, &numPendingBuffers);
+    mQueueBufferOutput.inflate(w, h, 0, numPendingBuffers);
+}
+
+void VirtualDisplaySurface::resetPerFrameState() {
+    mCompositionType = COMPOSITION_UNKNOWN;
+    mSinkBufferWidth = 0;
+    mSinkBufferHeight = 0;
+    mFbFence = Fence::NO_FENCE;
+    mFbProducerSlot = -1;
+    mOutputProducerSlot = -1;
+}
+
+// This slot mapping function is its own inverse, so two copies are unnecessary.
+// Both are kept to make the intent clear where the function is called, and for
+// the (unlikely) chance that we switch to a different mapping function.
+int VirtualDisplaySurface::mapSource2ProducerSlot(Source source, int sslot) {
+    if (source == SOURCE_SCRATCH) {
+        return BufferQueue::NUM_BUFFER_SLOTS - sslot - 1;
+    } else {
+        return sslot;
+    }
+}
+int VirtualDisplaySurface::mapProducer2SourceSlot(Source source, int pslot) {
+    return mapSource2ProducerSlot(source, pslot);
+}
+
+VirtualDisplaySurface::Source
+VirtualDisplaySurface::fbSourceForCompositionType(CompositionType type) {
+    return type == COMPOSITION_MIXED ? SOURCE_SCRATCH : SOURCE_SINK;
+}
+
+const char* VirtualDisplaySurface::dbgStateStr() const {
+    switch (mDbgState) {
+        case DBG_STATE_IDLE:      return "IDLE";
+        case DBG_STATE_PREPARED:  return "PREPARED";
+        case DBG_STATE_GLES:      return "GLES";
+        case DBG_STATE_GLES_DONE: return "GLES_DONE";
+        case DBG_STATE_HWC:       return "HWC";
+        default:                  return "INVALID";
+    }
+}
+
+const char* VirtualDisplaySurface::dbgSourceStr(Source s) {
+    switch (s) {
+        case SOURCE_SINK:    return "SINK";
+        case SOURCE_SCRATCH: return "SCRATCH";
+        default:             return "INVALID";
+    }
+}
+
 // ---------------------------------------------------------------------------
 } // namespace android
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index f321795..2b4cf8f 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -17,6 +17,9 @@
 #ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
 #define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
 
+#include <gui/ConsumerBase.h>
+#include <gui/IGraphicBufferProducer.h>
+
 #include "DisplaySurface.h"
 
 // ---------------------------------------------------------------------------
@@ -25,26 +28,187 @@
 
 class HWComposer;
 
-/* This DisplaySurface implementation is a stub used for developing HWC
- * virtual display support. It is currently just a passthrough.
+/* This DisplaySurface implementation supports virtual displays, where GLES
+ * and/or HWC compose into a buffer that is then passed to an arbitrary
+ * consumer (the sink) running in another process.
+ *
+ * The simplest case is when the virtual display will never use the h/w
+ * composer -- either the h/w composer doesn't support writing to buffers, or
+ * there are more virtual displays than it supports simultaneously. In this
+ * case, the GLES driver works directly with the output buffer queue, and
+ * calls to the VirtualDisplay from SurfaceFlinger and DisplayHardware do
+ * nothing.
+ *
+ * If h/w composer might be used, then each frame will fall into one of three
+ * configurations: GLES-only, HWC-only, and MIXED composition. In all of these,
+ * we must provide a FB target buffer and output buffer for the HWC set() call.
+ *
+ * In GLES-only composition, the GLES driver is given a buffer from the sink to
+ * render into. When the GLES driver queues the buffer to the
+ * VirtualDisplaySurface, the VirtualDisplaySurface holds onto it instead of
+ * immediately queueing it to the sink. The buffer is used as both the FB
+ * target and output buffer for HWC, though on these frames the HWC doesn't
+ * do any work for this display and doesn't write to the output buffer. After
+ * composition is complete, the buffer is queued to the sink.
+ *
+ * In HWC-only composition, the VirtualDisplaySurface dequeues a buffer from
+ * the sink and passes it to HWC as both the FB target buffer and output
+ * buffer. The HWC doesn't need to read from the FB target buffer, but does
+ * write to the output buffer. After composition is complete, the buffer is
+ * queued to the sink.
+ *
+ * On MIXED frames, things become more complicated, since some h/w composer
+ * implementations can't read from and write to the same buffer. This class has
+ * an internal BufferQueue that it uses as a scratch buffer pool. The GLES
+ * driver is given a scratch buffer to render into. When it finishes rendering,
+ * the buffer is queued and then immediately acquired by the
+ * VirtualDisplaySurface. The scratch buffer is then used as the FB target
+ * buffer for HWC, and a separate buffer is dequeued from the sink and used as
+ * the HWC output buffer. When HWC composition is complete, the scratch buffer
+ * is released and the output buffer is queued to the sink.
  */
-class VirtualDisplaySurface : public DisplaySurface {
+class VirtualDisplaySurface : public DisplaySurface,
+                              private BnGraphicBufferProducer,
+                              private ConsumerBase {
 public:
     VirtualDisplaySurface(HWComposer& hwc, int32_t dispId,
             const sp<IGraphicBufferProducer>& sink,
             const String8& name);
 
+    //
+    // DisplaySurface interface
+    //
     virtual sp<IGraphicBufferProducer> getIGraphicBufferProducer() const;
-
+    virtual status_t prepareFrame(CompositionType compositionType);
     virtual status_t compositionComplete();
     virtual status_t advanceFrame();
     virtual void onFrameCommitted();
     virtual void dump(String8& result) const;
 
 private:
+    enum Source {SOURCE_SINK = 0, SOURCE_SCRATCH = 1};
+
     virtual ~VirtualDisplaySurface();
 
-    sp<IGraphicBufferProducer> mSink;
+    //
+    // IGraphicBufferProducer interface, used by the GLES driver.
+    //
+    virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf);
+    virtual status_t setBufferCount(int bufferCount);
+    virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence,
+            uint32_t w, uint32_t h, uint32_t format, uint32_t usage);
+    virtual status_t queueBuffer(int pslot,
+            const QueueBufferInput& input, QueueBufferOutput* output);
+    virtual void cancelBuffer(int pslot, const sp<Fence>& fence);
+    virtual int query(int what, int* value);
+    virtual status_t setSynchronousMode(bool enabled);
+    virtual status_t connect(int api, QueueBufferOutput* output);
+    virtual status_t disconnect(int api);
+
+    //
+    // Utility methods
+    //
+    static Source fbSourceForCompositionType(CompositionType type);
+    status_t dequeueBuffer(Source source, uint32_t format,
+            int* sslot, sp<Fence>* fence);
+    void updateQueueBufferOutput(const QueueBufferOutput& qbo);
+    void resetPerFrameState();
+
+    // Both the sink and scratch buffer pools have their own set of slots
+    // ("source slots", or "sslot"). We have to merge these into the single
+    // set of slots used by the GLES producer ("producer slots" or "pslot") and
+    // internally in the VirtualDisplaySurface. To minimize the number of times
+    // a producer slot switches which source it comes from, we map source slot
+    // numbers to producer slot numbers differently for each source.
+    static int mapSource2ProducerSlot(Source source, int sslot);
+    static int mapProducer2SourceSlot(Source source, int pslot);
+
+    //
+    // Immutable after construction
+    //
+    HWComposer& mHwc;
+    const int32_t mDisplayId;
+    const String8 mDisplayName;
+    sp<IGraphicBufferProducer> mSource[2]; // indexed by SOURCE_*
+
+    //
+    // Inter-frame state
+    //
+
+    // To avoid buffer reallocations, we track the buffer usage requested by
+    // the GLES driver in dequeueBuffer so we can use the same flags on
+    // HWC-only frames.
+    uint32_t mProducerUsage;
+
+    // Since we present a single producer interface to the GLES driver, but
+    // are internally muxing between the sink and scratch producers, we have
+    // to keep track of which source last returned each producer slot from
+    // dequeueBuffer. Each bit in mLastSlotSource corresponds to a producer
+    // slot. Both mProducerSlotSource and mProducerBuffers are indexed by a
+    // "producer slot"; see the mapSlot*() functions.
+    uint32_t mProducerSlotSource;
+    sp<GraphicBuffer> mProducerBuffers[BufferQueue::NUM_BUFFER_SLOTS];
+
+    // The QueueBufferOutput with the latest info from the sink, and with the
+    // transform hint cleared. Since we defer queueBuffer from the GLES driver
+    // to the sink, we have to return the previous version.
+    QueueBufferOutput mQueueBufferOutput;
+
+    //
+    // Intra-frame state
+    //
+
+    // Composition type and GLES buffer source for the current frame.
+    // Valid after prepareFrame(), cleared in onFrameCommitted.
+    CompositionType mCompositionType;
+
+    // Details of the current sink buffer. These become valid when a buffer is
+    // dequeued from the sink, and are used when queueing the buffer.
+    uint32_t mSinkBufferWidth, mSinkBufferHeight;
+
+    // mFbFence is the fence HWC should wait for before reading the framebuffer
+    // target buffer.
+    sp<Fence> mFbFence;
+
+    // Producer slot numbers for the buffers to use for HWC framebuffer target
+    // and output.
+    int mFbProducerSlot;
+    int mOutputProducerSlot;
+
+    // Debug only -- track the sequence of events in each frame so we can make
+    // sure they happen in the order we expect. This class implicitly models
+    // a state machine; this enum/variable makes it explicit.
+    //
+    // +-----------+-------------------+-------------+
+    // | State     | Event             || Next State |
+    // +-----------+-------------------+-------------+
+    // | IDLE      | prepareFrame      || PREPARED   |
+    // | PREPARED  | dequeueBuffer [1] || GLES       |
+    // | PREPARED  | advanceFrame [2]  || HWC        |
+    // | GLES      | queueBuffer       || GLES_DONE  |
+    // | GLES_DONE | advanceFrame      || HWC        |
+    // | HWC       | onFrameCommitted  || IDLE       |
+    // +-----------+-------------------++------------+
+    // [1] COMPOSITION_GLES and COMPOSITION_MIXED frames.
+    // [2] COMPOSITION_HWC frames.
+    //
+    enum DbgState {
+        // no buffer dequeued, don't know anything about the next frame
+        DBG_STATE_IDLE,
+        // no buffer dequeued, but we know the buffer source for the frame
+        DBG_STATE_PREPARED,
+        // GLES driver has a buffer dequeued
+        DBG_STATE_GLES,
+        // GLES driver has queued the buffer, we haven't sent it to HWC yet
+        DBG_STATE_GLES_DONE,
+        // HWC has the buffer for this frame
+        DBG_STATE_HWC,
+    };
+    DbgState mDbgState;
+    CompositionType mDbgLastCompositionType;
+
+    const char* dbgStateStr() const;
+    static const char* dbgSourceStr(Source s);
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index f6bd676..35ac0c8 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -104,7 +104,7 @@
     // protected by mLock
     SortedVector< wp<Connection> > mDisplayEventConnections;
     Vector< DisplayEventReceiver::Event > mPendingEvents;
-    DisplayEventReceiver::Event mVSyncEvent[HWC_DISPLAY_TYPES_SUPPORTED];
+    DisplayEventReceiver::Event mVSyncEvent[HWC_NUM_DISPLAY_TYPES];
     bool mUseSoftwareVSync;
 
     // for debugging
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f31d650..2962115 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -110,8 +110,8 @@
 {
     // Creates a custom BufferQueue for SurfaceFlingerConsumer to use
     sp<BufferQueue> bq = new SurfaceTextureLayer(mFlinger);
-    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(mTextureName, true,
-            GL_TEXTURE_EXTERNAL_OES, false, bq);
+    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(bq, mTextureName,
+            GL_TEXTURE_EXTERNAL_OES, false);
 
     mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
     mSurfaceFlingerConsumer->setFrameAvailableListener(this);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index ecf9fa7..9adabe8 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -895,6 +895,11 @@
 
         status_t err = hwc.prepare();
         ALOGE_IF(err, "HWComposer::prepare failed (%s)", strerror(-err));
+
+        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+            sp<const DisplayDevice> hw(mDisplays[dpy]);
+            hw->prepareFrame(hwc);
+        }
     }
 }
 
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
index d774c33..5de6d12 100644
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ b/services/surfaceflinger/SurfaceFlingerConsumer.h
@@ -27,11 +27,10 @@
  */
 class SurfaceFlingerConsumer : public GLConsumer {
 public:
-    SurfaceFlingerConsumer(GLuint tex, bool allowSynchronousMode = true,
-            GLenum texTarget = GL_TEXTURE_EXTERNAL_OES, bool useFenceSync = true,
-            const sp<BufferQueue> &bufferQueue = 0)
-        : GLConsumer(tex, allowSynchronousMode, texTarget, useFenceSync,
-            bufferQueue)
+    SurfaceFlingerConsumer(const sp<BufferQueue>& bq, GLuint tex,
+            GLenum texTarget = GL_TEXTURE_EXTERNAL_OES,
+            bool useFenceSync = true)
+        : GLConsumer(bq, tex, texTarget, useFenceSync)
     {}
 
     class BufferRejecter {