Merge "Correct setLayer variants."
diff --git a/cmds/cmd/Android.mk b/cmds/cmd/Android.mk
index d565e57..4868555 100644
--- a/cmds/cmd/Android.mk
+++ b/cmds/cmd/Android.mk
@@ -10,6 +10,8 @@
     libselinux \
 	libbinder
 
+LOCAL_CFLAGS := -Wall -Werror
+
 LOCAL_C_INCLUDES += \
     $(JNI_H_INCLUDE)
 
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index 6511b44..48d5d4a 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -104,7 +104,7 @@
         if (is_selinux_enabled() && seLinuxContext.size() > 0) {
             String8 seLinuxContext8(seLinuxContext);
             security_context_t tmp = NULL;
-            int ret = getfilecon(fullPath.string(), &tmp);
+            getfilecon(fullPath.string(), &tmp);
             Unique_SecurityContext context(tmp);
             if (checkWrite) {
                 int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 4b67d8f..b97df35 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -691,7 +691,9 @@
     printf("Kernel: ");
     DumpFileToFd(STDOUT_FILENO, "", "/proc/version");
     printf("Command line: %s\n", strtok(cmdline_buf, "\n"));
-    ds.RunCommand("UPTIME", {"uptime"}, CommandOptions::DEFAULT);
+    printf("Uptime: ");
+    RunCommandToFd(STDOUT_FILENO, "", {"uptime", "-p"},
+                   CommandOptions::WithTimeout(1).Always().Build());
     printf("Bugreport format version: %s\n", version_.c_str());
     printf("Dumpstate info: id=%d pid=%d dry_run=%d args=%s extra_options=%s\n", id_, pid_,
            PropertiesHelper::IsDryRun(), args_.c_str(), extra_options_.c_str());
@@ -1093,7 +1095,6 @@
     DurationReporter duration_reporter("DUMPSTATE");
 
     dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
-    /* TODO: Remove duplicate uptime call when tools use it from header */
     RunCommand("UPTIME", {"uptime"});
     DumpBlockStatFiles();
     dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
@@ -1190,19 +1191,6 @@
 
     RunCommand("LAST RADIO LOG", {"parse_radio_log", "/proc/last_radio_log"});
 
-    printf("------ BACKLIGHTS ------\n");
-    printf("LCD brightness=");
-    DumpFile("", "/sys/class/leds/lcd-backlight/brightness");
-    printf("Button brightness=");
-    DumpFile("", "/sys/class/leds/button-backlight/brightness");
-    printf("Keyboard brightness=");
-    DumpFile("", "/sys/class/leds/keyboard-backlight/brightness");
-    printf("ALS mode=");
-    DumpFile("", "/sys/class/leds/lcd-backlight/als");
-    printf("LCD driver registers:\n");
-    DumpFile("", "/sys/class/leds/lcd-backlight/registers");
-    printf("\n");
-
     /* Binder state is expensive to look at as it uses a lot of memory. */
     DumpFile("BINDER FAILED TRANSACTION LOG", "/sys/kernel/debug/binder/failed_transaction_log");
     DumpFile("BINDER TRANSACTION LOG", "/sys/kernel/debug/binder/transaction_log");
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 48d5b36..715bf8c 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -1863,13 +1863,13 @@
     return ok();
 }
 
-binder::Status InstalldNativeService::snapshotProfile(int32_t appId, const std::string& packageName,
-        const std::string& codePath, bool* _aidl_return) {
+binder::Status InstalldNativeService::createProfileSnapshot(int32_t appId,
+        const std::string& packageName, const std::string& codePath, bool* _aidl_return) {
     ENFORCE_UID(AID_SYSTEM);
     CHECK_ARGUMENT_PACKAGE_NAME(packageName);
     std::lock_guard<std::recursive_mutex> lock(mLock);
 
-    *_aidl_return = snapshot_profile(appId, packageName, codePath);
+    *_aidl_return = create_profile_snapshot(appId, packageName, codePath);
     return ok();
 }
 
diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h
index eb7231c..57dd834 100644
--- a/cmds/installd/InstalldNativeService.h
+++ b/cmds/installd/InstalldNativeService.h
@@ -96,7 +96,7 @@
     binder::Status clearAppProfiles(const std::string& packageName);
     binder::Status destroyAppProfiles(const std::string& packageName);
 
-    binder::Status snapshotProfile(int32_t appId, const std::string& packageName,
+    binder::Status createProfileSnapshot(int32_t appId, const std::string& packageName,
             const std::string& codePath, bool* _aidl_return);
     binder::Status destroyProfileSnapshot(const std::string& packageName,
             const std::string& codePath);
diff --git a/cmds/installd/binder/android/os/IInstalld.aidl b/cmds/installd/binder/android/os/IInstalld.aidl
index 16ba2af..394c028 100644
--- a/cmds/installd/binder/android/os/IInstalld.aidl
+++ b/cmds/installd/binder/android/os/IInstalld.aidl
@@ -62,7 +62,8 @@
     void clearAppProfiles(@utf8InCpp String packageName);
     void destroyAppProfiles(@utf8InCpp String packageName);
 
-    boolean snapshotProfile(int appId, @utf8InCpp String packageName, @utf8InCpp String codePath);
+    boolean createProfileSnapshot(int appId, @utf8InCpp String packageName,
+            @utf8InCpp String codePath);
     void destroyProfileSnapshot(@utf8InCpp String packageName, @utf8InCpp String codePath);
 
     void idmap(@utf8InCpp String targetApkPath, @utf8InCpp String overlayApkPath, int uid);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index beffe00..ee3e1dc 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -963,7 +963,7 @@
   if (EndsWith(oat_path, ".dex")) {
     std::string new_path = oat_path;
     new_path.replace(new_path.length() - strlen(".dex"), strlen(".dex"), new_ext);
-    CHECK(EndsWith(new_path, new_ext.c_str()));
+    CHECK(EndsWith(new_path, new_ext));
     return new_path;
   }
 
@@ -2399,7 +2399,7 @@
     }
 }
 
-bool snapshot_profile(int32_t app_id, const std::string& package_name,
+bool create_profile_snapshot(int32_t app_id, const std::string& package_name,
         const std::string& code_path) {
     int app_shared_gid = multiuser_get_shared_gid(/*user_id*/ 0, app_id);
 
diff --git a/cmds/installd/dexopt.h b/cmds/installd/dexopt.h
index 8a9ffd2..496f594 100644
--- a/cmds/installd/dexopt.h
+++ b/cmds/installd/dexopt.h
@@ -59,7 +59,8 @@
 // ownership is assigned to AID_SYSTEM.
 // The snapshot location is reference_profile_location.snapshot. If a snapshot is already
 // there, it will be truncated and overwritten.
-bool snapshot_profile(int32_t app_id, const std::string& package, const std::string& code_path);
+bool create_profile_snapshot(int32_t app_id, const std::string& package,
+        const std::string& code_path);
 
 bool dump_profiles(int32_t uid, const std::string& pkgname, const char* code_paths);
 
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 0c2d341..d938d8a 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -882,7 +882,7 @@
         //        backs to do weird things.)
         const char* apk_path = package_parameters_.apk_path;
         CHECK(apk_path != nullptr);
-        if (StartsWith(apk_path, android_root_.c_str())) {
+        if (StartsWith(apk_path, android_root_)) {
             const char* last_slash = strrchr(apk_path, '/');
             if (last_slash != nullptr) {
                 std::string path(apk_path, last_slash - apk_path + 1);
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index 05d7b6c..eaf0aa1 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -451,9 +451,10 @@
         }
     }
 
-    void SnapshotProfile(int32_t appid, const std::string& package_name, bool expected_result) {
+    void createProfileSnapshot(int32_t appid, const std::string& package_name,
+            bool expected_result) {
         bool result;
-        binder::Status binder_result = service_->snapshotProfile(
+        binder::Status binder_result = service_->createProfileSnapshot(
                 appid, package_name, "base.jar", &result);
         ASSERT_TRUE(binder_result.isOk());
         ASSERT_EQ(expected_result, result);
@@ -531,7 +532,7 @@
     LOG(INFO) << "ProfileSnapshotOk";
 
     SetupProfiles(/*setup_ref*/ true);
-    SnapshotProfile(kTestAppId, package_name_, /*expected_result*/ true);
+    createProfileSnapshot(kTestAppId, package_name_, /*expected_result*/ true);
 }
 
 // The reference profile is created on the fly. We need to be able to
@@ -540,21 +541,21 @@
     LOG(INFO) << "ProfileSnapshotOkNoReference";
 
     SetupProfiles(/*setup_ref*/ false);
-    SnapshotProfile(kTestAppId, package_name_, /*expected_result*/ true);
+    createProfileSnapshot(kTestAppId, package_name_, /*expected_result*/ true);
 }
 
 TEST_F(ProfileTest, ProfileSnapshotFailWrongPackage) {
     LOG(INFO) << "ProfileSnapshotFailWrongPackage";
 
     SetupProfiles(/*setup_ref*/ true);
-    SnapshotProfile(kTestAppId, "not.there", /*expected_result*/ false);
+    createProfileSnapshot(kTestAppId, "not.there", /*expected_result*/ false);
 }
 
 TEST_F(ProfileTest, ProfileSnapshotDestroySnapshot) {
     LOG(INFO) << "ProfileSnapshotDestroySnapshot";
 
     SetupProfiles(/*setup_ref*/ true);
-    SnapshotProfile(kTestAppId, package_name_, /*expected_result*/ true);
+    createProfileSnapshot(kTestAppId, package_name_, /*expected_result*/ true);
 
     binder::Status binder_result = service_->destroyProfileSnapshot(package_name_, "base.jar");
     ASSERT_TRUE(binder_result.isOk());
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
index d336a43..4d93cb4 100644
--- a/cmds/servicemanager/servicemanager.rc
+++ b/cmds/servicemanager/servicemanager.rc
@@ -11,5 +11,7 @@
     onrestart restart inputflinger
     onrestart restart drm
     onrestart restart cameraserver
+    onrestart restart keystore
+    onrestart restart gatekeeperd
     writepid /dev/cpuset/system-background/tasks
     shutdown critical
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index c4b5dca..6187528 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -31,7 +31,6 @@
 #include <utils/Errors.h>
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
-#include <utils/String8.h>
 #include <utils/Vector.h>
 #include <utils/BitSet.h>
 
@@ -142,16 +141,16 @@
     virtual ~InputChannel();
 
 public:
-    InputChannel(const String8& name, int fd);
+    InputChannel(const std::string& name, int fd);
 
     /* Creates a pair of input channels.
      *
      * Returns OK on success.
      */
-    static status_t openInputChannelPair(const String8& name,
+    static status_t openInputChannelPair(const std::string& name,
             sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel);
 
-    inline String8 getName() const { return mName; }
+    inline std::string getName() const { return mName; }
     inline int getFd() const { return mFd; }
 
     /* Sends a message to the other endpoint.
@@ -183,7 +182,7 @@
     sp<InputChannel> dup() const;
 
 private:
-    String8 mName;
+    std::string mName;
     int mFd;
 };
 
diff --git a/libs/binder/ActivityManager.cpp b/libs/binder/ActivityManager.cpp
new file mode 100644
index 0000000..2904718
--- /dev/null
+++ b/libs/binder/ActivityManager.cpp
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2017 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 <mutex>
+#include <binder/ActivityManager.h>
+#include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+
+#include <utils/SystemClock.h>
+
+namespace android {
+
+ActivityManager::ActivityManager()
+{
+}
+
+sp<IActivityManager> ActivityManager::getService()
+{
+    std::lock_guard<Mutex> scoped_lock(mLock);
+    int64_t startTime = 0;
+    sp<IActivityManager> service = mService;
+    while (service == NULL || !IInterface::asBinder(service)->isBinderAlive()) {
+        sp<IBinder> binder = defaultServiceManager()->checkService(String16("activity"));
+        if (binder == NULL) {
+            // Wait for the activity service to come back...
+            if (startTime == 0) {
+                startTime = uptimeMillis();
+                ALOGI("Waiting for activity service");
+            } else if ((uptimeMillis() - startTime) > 10000) {
+                ALOGW("Waiting too long for activity service, giving up");
+                service = NULL;
+                break;
+            }
+            sleep(1);
+        } else {
+            service = interface_cast<IActivityManager>(binder);
+            mService = service;
+        }
+    }
+    return service;
+}
+
+int ActivityManager::openContentUri(const String16& stringUri)
+{
+    sp<IActivityManager> service = getService();
+    return service != NULL ? service->openContentUri(stringUri) : -1;
+}
+
+void ActivityManager::registerUidObserver(const sp<IUidObserver>& observer,
+                                          const int32_t event,
+                                          const int32_t cutpoint,
+                                          const String16& callingPackage)
+{
+    sp<IActivityManager> service = getService();
+    if (service != NULL) {
+        service->registerUidObserver(observer, event, cutpoint, callingPackage);
+    }
+}
+
+void ActivityManager::unregisterUidObserver(const sp<IUidObserver>& observer)
+{
+    sp<IActivityManager> service = getService();
+    if (service != NULL) {
+        service->unregisterUidObserver(observer);
+    }
+}
+
+}; // namespace android
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index c130087..2a07cd1 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -38,6 +38,7 @@
     },
 
     srcs: [
+        "ActivityManager.cpp",
         "AppOpsManager.cpp",
         "Binder.cpp",
         "BpBinder.cpp",
@@ -56,6 +57,7 @@
         "IResultReceiver.cpp",
         "IServiceManager.cpp",
         "IShellCallback.cpp",
+        "IUidObserver.cpp",
         "MemoryBase.cpp",
         "MemoryDealer.cpp",
         "MemoryHeapBase.cpp",
diff --git a/libs/binder/IActivityManager.cpp b/libs/binder/IActivityManager.cpp
index 50a8b28..b7a5fd9 100644
--- a/libs/binder/IActivityManager.cpp
+++ b/libs/binder/IActivityManager.cpp
@@ -56,6 +56,28 @@
         }
         return fd;
     }
+
+    virtual void registerUidObserver(const sp<IUidObserver>& observer,
+                                     const int32_t event,
+                                     const int32_t cutpoint,
+                                     const String16& callingPackage)
+    {
+         Parcel data, reply;
+         data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
+         data.writeStrongBinder(IInterface::asBinder(observer));
+         data.writeInt32(event);
+         data.writeInt32(cutpoint);
+         data.writeString16(callingPackage);
+         remote()->transact(REGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+    }
+
+    virtual void unregisterUidObserver(const sp<IUidObserver>& observer)
+    {
+         Parcel data, reply;
+         data.writeInterfaceToken(IActivityManager::getInterfaceDescriptor());
+         data.writeStrongBinder(IInterface::asBinder(observer));
+         remote()->transact(UNREGISTER_UID_OBSERVER_TRANSACTION, data, &reply);
+    }
 };
 
 // ------------------------------------------------------------------------------------
diff --git a/libs/binder/IUidObserver.cpp b/libs/binder/IUidObserver.cpp
new file mode 100644
index 0000000..697e948
--- /dev/null
+++ b/libs/binder/IUidObserver.cpp
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2017 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/IUidObserver.h>
+
+#include <binder/Parcel.h>
+
+namespace android {
+
+// ------------------------------------------------------------------------------------
+
+class BpUidObserver : public BpInterface<IUidObserver>
+{
+public:
+    explicit BpUidObserver(const sp<IBinder>& impl)
+        : BpInterface<IUidObserver>(impl)
+    {
+    }
+
+    virtual void onUidGone(uid_t uid, bool disabled)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
+        data.writeInt32((int32_t) uid);
+        data.writeInt32(disabled ? 1 : 0);
+        remote()->transact(ON_UID_GONE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual void onUidActive(uid_t uid)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
+        data.writeInt32((int32_t) uid);
+        remote()->transact(ON_UID_ACTIVE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+
+    virtual void onUidIdle(uid_t uid, bool disabled)
+    {
+        Parcel data, reply;
+        data.writeInterfaceToken(IUidObserver::getInterfaceDescriptor());
+        data.writeInt32((int32_t) uid);
+        data.writeInt32(disabled ? 1 : 0);
+        remote()->transact(ON_UID_IDLE_TRANSACTION, data, &reply, IBinder::FLAG_ONEWAY);
+    }
+};
+
+// ----------------------------------------------------------------------
+
+IMPLEMENT_META_INTERFACE(UidObserver, "android.app.IUidObserver");
+
+// ----------------------------------------------------------------------
+
+status_t BnUidObserver::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+    switch(code) {
+        case ON_UID_GONE_TRANSACTION: {
+            CHECK_INTERFACE(IUidObserver, data, reply);
+            uid_t uid = data.readInt32();
+            bool disabled = data.readInt32() == 1;
+            onUidGone(uid, disabled);
+            return NO_ERROR;
+        } break;
+
+        case ON_UID_ACTIVE_TRANSACTION: {
+            CHECK_INTERFACE(IUidObserver, data, reply);
+            uid_t uid = data.readInt32();
+            onUidActive(uid);
+            return NO_ERROR;
+        } break;
+
+        case ON_UID_IDLE_TRANSACTION: {
+            CHECK_INTERFACE(IUidObserver, data, reply);
+            uid_t uid = data.readInt32();
+            bool disabled = data.readInt32() == 1;
+            onUidIdle(uid, disabled);
+            return NO_ERROR;
+        } break;
+        default:
+            return BBinder::onTransact(code, data, reply, flags);
+    }
+}
+
+}; // namespace android
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index 44039f8..597fca9 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -86,6 +86,12 @@
         }
         LOG_ALWAYS_FATAL("ProcessState was already initialized.");
     }
+
+    if (access(driver, R_OK) == -1) {
+        ALOGE("Binder driver %s is unavailable. Using /dev/binder instead.", driver);
+        driver = "/dev/binder";
+    }
+
     gProcess = new ProcessState(driver);
     return gProcess;
 }
@@ -420,7 +426,7 @@
         mVMStart = mmap(0, BINDER_VM_SIZE, PROT_READ, MAP_PRIVATE | MAP_NORESERVE, mDriverFD, 0);
         if (mVMStart == MAP_FAILED) {
             // *sigh*
-            ALOGE("Using /dev/binder failed: unable to mmap transaction memory.\n");
+            ALOGE("Using %s failed: unable to mmap transaction memory.\n", mDriverName.c_str());
             close(mDriverFD);
             mDriverFD = -1;
             mDriverName.clear();
diff --git a/libs/binder/include/binder/ActivityManager.h b/libs/binder/include/binder/ActivityManager.h
new file mode 100644
index 0000000..408c428
--- /dev/null
+++ b/libs/binder/include/binder/ActivityManager.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 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_ACTIVITY_MANAGER_H
+#define ANDROID_ACTIVITY_MANAGER_H
+
+#include <binder/IActivityManager.h>
+
+#include <utils/threads.h>
+
+// ---------------------------------------------------------------------------
+namespace android {
+
+class ActivityManager
+{
+public:
+
+    enum {
+        // Flag for registerUidObserver: report uid gone
+        UID_OBSERVER_GONE = 1<<1,
+        // Flag for registerUidObserver: report uid has become idle
+        UID_OBSERVER_IDLE = 1<<2,
+        // Flag for registerUidObserver: report uid has become active
+        UID_OBSERVER_ACTIVE = 1<<3
+    };
+
+    enum {
+        // Not a real process state
+        PROCESS_STATE_UNKNOWN = -1
+    };
+
+    ActivityManager();
+
+    int openContentUri(const String16& stringUri);
+    void registerUidObserver(const sp<IUidObserver>& observer,
+                             const int32_t event,
+                             const int32_t cutpoint,
+                             const String16& callingPackage);
+    void unregisterUidObserver(const sp<IUidObserver>& observer);
+
+private:
+    Mutex mLock;
+    sp<IActivityManager> mService;
+    sp<IActivityManager> getService();
+};
+
+
+}; // namespace android
+// ---------------------------------------------------------------------------
+#endif // ANDROID_ACTIVITY_MANAGER_H
diff --git a/libs/binder/include/binder/IActivityManager.h b/libs/binder/include/binder/IActivityManager.h
index 5ad2180..bac2a99 100644
--- a/libs/binder/include/binder/IActivityManager.h
+++ b/libs/binder/include/binder/IActivityManager.h
@@ -18,6 +18,7 @@
 #define ANDROID_IACTIVITY_MANAGER_H
 
 #include <binder/IInterface.h>
+#include <binder/IUidObserver.h>
 
 namespace android {
 
@@ -28,10 +29,17 @@
 public:
     DECLARE_META_INTERFACE(ActivityManager)
 
-    virtual int openContentUri(const String16& /* stringUri */) = 0;
+    virtual int openContentUri(const String16& stringUri) = 0;
+    virtual void registerUidObserver(const sp<IUidObserver>& observer,
+                                     const int32_t event,
+                                     const int32_t cutpoint,
+                                     const String16& callingPackage) = 0;
+    virtual void unregisterUidObserver(const sp<IUidObserver>& observer) = 0;
 
     enum {
-        OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION
+        OPEN_CONTENT_URI_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+        REGISTER_UID_OBSERVER_TRANSACTION,
+        UNREGISTER_UID_OBSERVER_TRANSACTION
     };
 };
 
@@ -39,4 +47,4 @@
 
 }; // namespace android
 
-#endif // ANDROID_IACTIVITY_MANAGER_H
\ No newline at end of file
+#endif // ANDROID_IACTIVITY_MANAGER_H
diff --git a/libs/binder/include/binder/IUidObserver.h b/libs/binder/include/binder/IUidObserver.h
new file mode 100644
index 0000000..fd4d8a6
--- /dev/null
+++ b/libs/binder/include/binder/IUidObserver.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2017 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_IUID_OBSERVER_H
+#define ANDROID_IUID_OBSERVER_H
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IUidObserver : public IInterface
+{
+public:
+    DECLARE_META_INTERFACE(UidObserver)
+
+    virtual void onUidGone(uid_t uid, bool disabled) = 0;
+    virtual void onUidActive(uid_t uid) = 0;
+    virtual void onUidIdle(uid_t uid, bool disabled) = 0;
+
+    enum {
+        ON_UID_GONE_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION,
+        ON_UID_ACTIVE_TRANSACTION,
+        ON_UID_IDLE_TRANSACTION
+    };
+};
+
+// ----------------------------------------------------------------------
+
+class BnUidObserver : public BnInterface<IUidObserver>
+{
+public:
+    virtual status_t  onTransact(uint32_t code,
+                                 const Parcel& data,
+                                 Parcel* reply,
+                                 uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IUID_OBSERVER_H
diff --git a/libs/binder/tests/binderDriverInterfaceTest.cpp b/libs/binder/tests/binderDriverInterfaceTest.cpp
index b14631d..4f00bc1 100644
--- a/libs/binder/tests/binderDriverInterfaceTest.cpp
+++ b/libs/binder/tests/binderDriverInterfaceTest.cpp
@@ -77,6 +77,16 @@
         virtual void TearDown() {
         }
     protected:
+        /* The ioctl must either return 0, or if it doesn't errno should be accepted_errno */
+        void binderTestIoctlSuccessOrError(int cmd, void *arg, int accepted_errno) {
+            int ret;
+
+            ret = ioctl(m_binderFd, cmd, arg);
+            if (ret != 0) {
+                EXPECT_EQ(errno, accepted_errno);
+            }
+        }
+
         void binderTestIoctlRetErr2(int cmd, void *arg, int expect_ret, int expect_errno, int accept_errno) {
             int ret;
 
@@ -256,7 +266,7 @@
 
     {
         SCOPED_TRACE("1st WriteRead");
-        binderTestIoctl(BINDER_WRITE_READ, &bwr);
+        binderTestIoctlSuccessOrError(BINDER_WRITE_READ, &bwr, EAGAIN);
     }
     EXPECT_EQ(sizeof(bc1), bwr.write_consumed);
     if (bwr.read_consumed < offsetof(typeof(br), pad)) {
diff --git a/libs/graphicsenv/Android.bp b/libs/graphicsenv/Android.bp
index 9f99538..4da30e9 100644
--- a/libs/graphicsenv/Android.bp
+++ b/libs/graphicsenv/Android.bp
@@ -22,7 +22,6 @@
     cflags: ["-Wall", "-Werror"],
 
     shared_libs: [
-        "libnativeloader",
         "liblog",
     ],
 
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index f46e9f6..961f101 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -20,13 +20,23 @@
 
 #include <mutex>
 
+#include <android/dlext.h>
 #include <log/log.h>
-#include <nativeloader/dlext_namespaces.h>
-#include <nativeloader/native_loader.h>
 
 // TODO(b/37049319) Get this from a header once one exists
 extern "C" {
   android_namespace_t* android_get_exported_namespace(const char*);
+  android_namespace_t* android_create_namespace(const char* name,
+                                                const char* ld_library_path,
+                                                const char* default_library_path,
+                                                uint64_t type,
+                                                const char* permitted_when_isolated_path,
+                                                android_namespace_t* parent);
+
+  enum {
+     ANDROID_NAMESPACE_TYPE_ISOLATED = 1,
+     ANDROID_NAMESPACE_TYPE_SHARED = 2,
+  };
 }
 
 namespace android {
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index cf72d55..c713e9e 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -19,7 +19,7 @@
 
 cc_library_shared {
     name: "libgui",
-    vendor_available: true,
+    vendor_available: false,
     vndk: {
         enabled: true,
     },
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index da42956..34e6d80 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -49,16 +49,6 @@
 
 BufferItemConsumer::~BufferItemConsumer() {}
 
-void BufferItemConsumer::setName(const String8& name) {
-    Mutex::Autolock _l(mMutex);
-    if (mAbandoned) {
-        BI_LOGE("setName: BufferItemConsumer is abandoned!");
-        return;
-    }
-    mName = name;
-    mConsumer->setConsumerName(name);
-}
-
 void BufferItemConsumer::setBufferFreedListener(
         const wp<BufferFreedListener>& listener) {
     Mutex::Autolock _l(mMutex);
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index 7aa7872..f9e292e 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -182,6 +182,16 @@
     return mAbandoned;
 }
 
+void ConsumerBase::setName(const String8& name) {
+    Mutex::Autolock _l(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("setName: ConsumerBase is abandoned!");
+        return;
+    }
+    mName = name;
+    mConsumer->setConsumerName(name);
+}
+
 void ConsumerBase::setFrameAvailableListener(
         const wp<FrameAvailableListener>& listener) {
     CB_LOGV("setFrameAvailableListener");
@@ -237,6 +247,50 @@
     return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
 }
 
+status_t ConsumerBase::setConsumerUsageBits(uint64_t usage) {
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("setConsumerUsageBits: ConsumerBase is abandoned!");
+        return NO_INIT;
+    }
+    return mConsumer->setConsumerUsageBits(usage);
+}
+
+status_t ConsumerBase::setTransformHint(uint32_t hint) {
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("setTransformHint: ConsumerBase is abandoned!");
+        return NO_INIT;
+    }
+    return mConsumer->setTransformHint(hint);
+}
+
+status_t ConsumerBase::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("setMaxAcquiredBufferCount: ConsumerBase is abandoned!");
+        return NO_INIT;
+    }
+    return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers);
+}
+
+sp<NativeHandle> ConsumerBase::getSidebandStream() const {
+    Mutex::Autolock _l(mMutex);
+    if (mAbandoned) {
+        CB_LOGE("getSidebandStream: ConsumerBase is abandoned!");
+        return nullptr;
+    }
+
+    sp<NativeHandle> stream;
+    status_t err = mConsumer->getSidebandStream(&stream);
+    if (err != NO_ERROR) {
+        CB_LOGE("failed to get sideband stream: %d", err);
+        return nullptr;
+    }
+
+    return stream;
+}
+
 status_t ConsumerBase::getOccupancyHistory(bool forceFlush,
         std::vector<OccupancyTracker::Segment>* outHistory) {
     Mutex::Autolock _l(mMutex);
diff --git a/libs/gui/CpuConsumer.cpp b/libs/gui/CpuConsumer.cpp
index ae7c65c..8edf604 100644
--- a/libs/gui/CpuConsumer.cpp
+++ b/libs/gui/CpuConsumer.cpp
@@ -18,11 +18,11 @@
 #define LOG_TAG "CpuConsumer"
 //#define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
-#include <cutils/compiler.h>
-#include <utils/Log.h>
-#include <gui/BufferItem.h>
 #include <gui/CpuConsumer.h>
 
+#include <gui/BufferItem.h>
+#include <utils/Log.h>
+
 #define CC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
 //#define CC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
 //#define CC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
@@ -44,20 +44,19 @@
     mConsumer->setMaxAcquiredBufferCount(static_cast<int32_t>(maxLockedBuffers));
 }
 
-CpuConsumer::~CpuConsumer() {
-    // ConsumerBase destructor does all the work.
+size_t CpuConsumer::findAcquiredBufferLocked(uintptr_t id) const {
+    for (size_t i = 0; i < mMaxLockedBuffers; i++) {
+        const auto& ab = mAcquiredBuffers[i];
+        // note that this finds AcquiredBuffer::kUnusedId as well
+        if (ab.mLockedBufferId == id) {
+            return i;
+        }
+    }
+    return mMaxLockedBuffers; // an invalid index
 }
 
-
-
-void CpuConsumer::setName(const String8& name) {
-    Mutex::Autolock _l(mMutex);
-    if (mAbandoned) {
-        CC_LOGE("setName: CpuConsumer is abandoned!");
-        return;
-    }
-    mName = name;
-    mConsumer->setConsumerName(name);
+static uintptr_t getLockedBufferId(const CpuConsumer::LockedBuffer& buffer) {
+    return reinterpret_cast<uintptr_t>(buffer.data);
 }
 
 static bool isPossiblyYUV(PixelFormat format) {
@@ -88,10 +87,74 @@
     }
 }
 
+status_t CpuConsumer::lockBufferItem(const BufferItem& item, LockedBuffer* outBuffer) const {
+    android_ycbcr ycbcr = android_ycbcr();
+
+    PixelFormat format = item.mGraphicBuffer->getPixelFormat();
+    PixelFormat flexFormat = format;
+    if (isPossiblyYUV(format)) {
+        int fenceFd = item.mFence.get() ? item.mFence->dup() : -1;
+        status_t err = item.mGraphicBuffer->lockAsyncYCbCr(GraphicBuffer::USAGE_SW_READ_OFTEN,
+                                                           item.mCrop, &ycbcr, fenceFd);
+        if (err == OK) {
+            flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
+            if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) {
+                CC_LOGV("locking buffer of format %#x as flex YUV", format);
+            }
+        } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
+            CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)", strerror(-err), err);
+            return err;
+        }
+    }
+
+    if (ycbcr.y != nullptr) {
+        outBuffer->data = reinterpret_cast<uint8_t*>(ycbcr.y);
+        outBuffer->stride = static_cast<uint32_t>(ycbcr.ystride);
+        outBuffer->dataCb = reinterpret_cast<uint8_t*>(ycbcr.cb);
+        outBuffer->dataCr = reinterpret_cast<uint8_t*>(ycbcr.cr);
+        outBuffer->chromaStride = static_cast<uint32_t>(ycbcr.cstride);
+        outBuffer->chromaStep = static_cast<uint32_t>(ycbcr.chroma_step);
+    } else {
+        // not flexible YUV; try lockAsync
+        void* bufferPointer = nullptr;
+        int fenceFd = item.mFence.get() ? item.mFence->dup() : -1;
+        status_t err = item.mGraphicBuffer->lockAsync(GraphicBuffer::USAGE_SW_READ_OFTEN,
+                                                      item.mCrop, &bufferPointer, fenceFd);
+        if (err != OK) {
+            CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)", strerror(-err), err);
+            return err;
+        }
+
+        outBuffer->data = reinterpret_cast<uint8_t*>(bufferPointer);
+        outBuffer->stride = item.mGraphicBuffer->getStride();
+        outBuffer->dataCb = nullptr;
+        outBuffer->dataCr = nullptr;
+        outBuffer->chromaStride = 0;
+        outBuffer->chromaStep = 0;
+    }
+
+    outBuffer->width = item.mGraphicBuffer->getWidth();
+    outBuffer->height = item.mGraphicBuffer->getHeight();
+    outBuffer->format = format;
+    outBuffer->flexFormat = flexFormat;
+
+    outBuffer->crop = item.mCrop;
+    outBuffer->transform = item.mTransform;
+    outBuffer->scalingMode = item.mScalingMode;
+    outBuffer->timestamp = item.mTimestamp;
+    outBuffer->dataSpace = item.mDataSpace;
+    outBuffer->frameNumber = item.mFrameNumber;
+
+    return OK;
+}
+
 status_t CpuConsumer::lockNextBuffer(LockedBuffer *nativeBuffer) {
     status_t err;
 
     if (!nativeBuffer) return BAD_VALUE;
+
+    Mutex::Autolock _l(mMutex);
+
     if (mCurrentLockedBuffers == mMaxLockedBuffers) {
         CC_LOGW("Max buffers have been locked (%zd), cannot lock anymore.",
                 mMaxLockedBuffers);
@@ -99,9 +162,6 @@
     }
 
     BufferItem b;
-
-    Mutex::Autolock _l(mMutex);
-
     err = acquireBufferLocked(&b, 0);
     if (err != OK) {
         if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
@@ -112,94 +172,23 @@
         }
     }
 
-    int slot = b.mSlot;
-
-    void *bufferPointer = NULL;
-    android_ycbcr ycbcr = android_ycbcr();
-
-    PixelFormat format = mSlots[slot].mGraphicBuffer->getPixelFormat();
-    PixelFormat flexFormat = format;
-    if (isPossiblyYUV(format)) {
-        if (b.mFence.get()) {
-            err = mSlots[slot].mGraphicBuffer->lockAsyncYCbCr(
-                GraphicBuffer::USAGE_SW_READ_OFTEN,
-                b.mCrop,
-                &ycbcr,
-                b.mFence->dup());
-        } else {
-            err = mSlots[slot].mGraphicBuffer->lockYCbCr(
-                GraphicBuffer::USAGE_SW_READ_OFTEN,
-                b.mCrop,
-                &ycbcr);
-        }
-        if (err == OK) {
-            bufferPointer = ycbcr.y;
-            flexFormat = HAL_PIXEL_FORMAT_YCbCr_420_888;
-            if (format != HAL_PIXEL_FORMAT_YCbCr_420_888) {
-                CC_LOGV("locking buffer of format %#x as flex YUV", format);
-            }
-        } else if (format == HAL_PIXEL_FORMAT_YCbCr_420_888) {
-            CC_LOGE("Unable to lock YCbCr buffer for CPU reading: %s (%d)",
-                    strerror(-err), err);
-            return err;
-        }
+    if (b.mGraphicBuffer == nullptr) {
+        b.mGraphicBuffer = mSlots[b.mSlot].mGraphicBuffer;
     }
 
-    if (bufferPointer == NULL) { // not flexible YUV
-        if (b.mFence.get()) {
-            err = mSlots[slot].mGraphicBuffer->lockAsync(
-                GraphicBuffer::USAGE_SW_READ_OFTEN,
-                b.mCrop,
-                &bufferPointer,
-                b.mFence->dup());
-        } else {
-            err = mSlots[slot].mGraphicBuffer->lock(
-                GraphicBuffer::USAGE_SW_READ_OFTEN,
-                b.mCrop,
-                &bufferPointer);
-        }
-        if (err != OK) {
-            CC_LOGE("Unable to lock buffer for CPU reading: %s (%d)",
-                    strerror(-err), err);
-            return err;
-        }
+    err = lockBufferItem(b, nativeBuffer);
+    if (err != OK) {
+        return err;
     }
 
-    size_t lockedIdx = 0;
-    for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) {
-        if (mAcquiredBuffers[lockedIdx].mSlot ==
-                BufferQueue::INVALID_BUFFER_SLOT) {
-            break;
-        }
-    }
-    assert(lockedIdx < mMaxLockedBuffers);
+    // find an unused AcquiredBuffer
+    size_t lockedIdx = findAcquiredBufferLocked(AcquiredBuffer::kUnusedId);
+    ALOG_ASSERT(lockedIdx < mMaxLockedBuffers);
+    AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx);
 
-    AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx);
-    ab.mSlot = slot;
-    ab.mBufferPointer = bufferPointer;
-    ab.mGraphicBuffer = mSlots[slot].mGraphicBuffer;
-
-    nativeBuffer->data   =
-            reinterpret_cast<uint8_t*>(bufferPointer);
-    nativeBuffer->width  = mSlots[slot].mGraphicBuffer->getWidth();
-    nativeBuffer->height = mSlots[slot].mGraphicBuffer->getHeight();
-    nativeBuffer->format = format;
-    nativeBuffer->flexFormat = flexFormat;
-    nativeBuffer->stride = (ycbcr.y != NULL) ?
-            static_cast<uint32_t>(ycbcr.ystride) :
-            mSlots[slot].mGraphicBuffer->getStride();
-
-    nativeBuffer->crop        = b.mCrop;
-    nativeBuffer->transform   = b.mTransform;
-    nativeBuffer->scalingMode = b.mScalingMode;
-    nativeBuffer->timestamp   = b.mTimestamp;
-    nativeBuffer->dataSpace   = b.mDataSpace;
-    nativeBuffer->frameNumber = b.mFrameNumber;
-
-    nativeBuffer->dataCb       = reinterpret_cast<uint8_t*>(ycbcr.cb);
-    nativeBuffer->dataCr       = reinterpret_cast<uint8_t*>(ycbcr.cr);
-    nativeBuffer->chromaStride = static_cast<uint32_t>(ycbcr.cstride);
-    nativeBuffer->chromaStep   = static_cast<uint32_t>(ycbcr.chroma_step);
+    ab.mSlot = b.mSlot;
+    ab.mGraphicBuffer = b.mGraphicBuffer;
+    ab.mLockedBufferId = getLockedBufferId(*nativeBuffer);
 
     mCurrentLockedBuffers++;
 
@@ -208,60 +197,34 @@
 
 status_t CpuConsumer::unlockBuffer(const LockedBuffer &nativeBuffer) {
     Mutex::Autolock _l(mMutex);
-    size_t lockedIdx = 0;
 
-    void *bufPtr = reinterpret_cast<void *>(nativeBuffer.data);
-    for (; lockedIdx < static_cast<size_t>(mMaxLockedBuffers); lockedIdx++) {
-        if (bufPtr == mAcquiredBuffers[lockedIdx].mBufferPointer) break;
-    }
+    uintptr_t id = getLockedBufferId(nativeBuffer);
+    size_t lockedIdx =
+        (id != AcquiredBuffer::kUnusedId) ? findAcquiredBufferLocked(id) : mMaxLockedBuffers;
     if (lockedIdx == mMaxLockedBuffers) {
         CC_LOGE("%s: Can't find buffer to free", __FUNCTION__);
         return BAD_VALUE;
     }
 
-    return releaseAcquiredBufferLocked(lockedIdx);
-}
+    AcquiredBuffer& ab = mAcquiredBuffers.editItemAt(lockedIdx);
 
-status_t CpuConsumer::releaseAcquiredBufferLocked(size_t lockedIdx) {
-    status_t err;
-    int fd = -1;
-
-    err = mAcquiredBuffers[lockedIdx].mGraphicBuffer->unlockAsync(&fd);
+    int fenceFd = -1;
+    status_t err = ab.mGraphicBuffer->unlockAsync(&fenceFd);
     if (err != OK) {
         CC_LOGE("%s: Unable to unlock graphic buffer %zd", __FUNCTION__,
                 lockedIdx);
         return err;
     }
-    int buf = mAcquiredBuffers[lockedIdx].mSlot;
-    if (CC_LIKELY(fd != -1)) {
-        sp<Fence> fence(new Fence(fd));
-        addReleaseFenceLocked(
-            mAcquiredBuffers[lockedIdx].mSlot,
-            mSlots[buf].mGraphicBuffer,
-            fence);
-    }
 
-    // release the buffer if it hasn't already been freed by the BufferQueue.
-    // This can happen, for example, when the producer of this buffer
-    // disconnected after this buffer was acquired.
-    if (CC_LIKELY(mAcquiredBuffers[lockedIdx].mGraphicBuffer ==
-            mSlots[buf].mGraphicBuffer)) {
-        releaseBufferLocked(
-                buf, mAcquiredBuffers[lockedIdx].mGraphicBuffer,
-                EGL_NO_DISPLAY, EGL_NO_SYNC_KHR);
-    }
+    sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
+    addReleaseFenceLocked(ab.mSlot, ab.mGraphicBuffer, fence);
+    releaseBufferLocked(ab.mSlot, ab.mGraphicBuffer);
 
-    AcquiredBuffer &ab = mAcquiredBuffers.editItemAt(lockedIdx);
-    ab.mSlot = BufferQueue::INVALID_BUFFER_SLOT;
-    ab.mBufferPointer = NULL;
-    ab.mGraphicBuffer.clear();
+    ab.reset();
 
     mCurrentLockedBuffers--;
-    return OK;
-}
 
-void CpuConsumer::freeBufferLocked(int slotIndex) {
-    ConsumerBase::freeBufferLocked(slotIndex);
+    return OK;
 }
 
 } // namespace android
diff --git a/libs/gui/FrameTimestamps.cpp b/libs/gui/FrameTimestamps.cpp
index fccca97..a379ad6 100644
--- a/libs/gui/FrameTimestamps.cpp
+++ b/libs/gui/FrameTimestamps.cpp
@@ -628,7 +628,6 @@
         ALOGE("FrameEventHistoryDelta assign clobbering history.");
     }
     mDeltas = std::move(src.mDeltas);
-    ALOGE_IF(src.mDeltas.empty(), "Source mDeltas not empty.");
     return *this;
 }
 
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 14d9937..788a6eb 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -31,6 +31,8 @@
 
 #include <hardware/hardware.h>
 
+#include <math/mat4.h>
+
 #include <gui/BufferItem.h>
 #include <gui/GLConsumer.h>
 #include <gui/ISurfaceComposer.h>
@@ -75,33 +77,7 @@
     "_______________"
 };
 
-// Transform matrices
-static float mtxIdentity[16] = {
-    1, 0, 0, 0,
-    0, 1, 0, 0,
-    0, 0, 1, 0,
-    0, 0, 0, 1,
-};
-static float mtxFlipH[16] = {
-    -1, 0, 0, 0,
-    0, 1, 0, 0,
-    0, 0, 1, 0,
-    1, 0, 0, 1,
-};
-static float mtxFlipV[16] = {
-    1, 0, 0, 0,
-    0, -1, 0, 0,
-    0, 0, 1, 0,
-    0, 1, 0, 1,
-};
-static float mtxRot90[16] = {
-    0, 1, 0, 0,
-    -1, 0, 0, 0,
-    0, 0, 1, 0,
-    1, 0, 0, 1,
-};
-
-static void mtxMul(float out[16], const float a[16], const float b[16]);
+static const mat4 mtxIdentity;
 
 Mutex GLConsumer::sStaticInitLock;
 sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer;
@@ -173,7 +149,7 @@
 {
     GLC_LOGV("GLConsumer");
 
-    memcpy(mCurrentTransformMatrix, mtxIdentity,
+    memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(),
             sizeof(mCurrentTransformMatrix));
 
     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
@@ -202,7 +178,7 @@
 {
     GLC_LOGV("GLConsumer");
 
-    memcpy(mCurrentTransformMatrix, mtxIdentity,
+    memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(),
             sizeof(mCurrentTransformMatrix));
 
     mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
@@ -758,25 +734,6 @@
     return OK;
 }
 
-bool GLConsumer::isExternalFormat(PixelFormat format)
-{
-    switch (format) {
-    // supported YUV formats
-    case HAL_PIXEL_FORMAT_YV12:
-    // Legacy/deprecated YUV formats
-    case HAL_PIXEL_FORMAT_YCbCr_422_SP:
-    case HAL_PIXEL_FORMAT_YCrCb_420_SP:
-    case HAL_PIXEL_FORMAT_YCbCr_422_I:
-        return true;
-    }
-
-    // Any OEM format needs to be considered
-    if (format>=0x100 && format<=0x1FF)
-        return true;
-
-    return false;
-}
-
 uint32_t GLConsumer::getCurrentTextureTarget() const {
     return mTexTarget;
 }
@@ -820,34 +777,37 @@
 void GLConsumer::computeTransformMatrix(float outTransform[16],
         const sp<GraphicBuffer>& buf, const Rect& cropRect, uint32_t transform,
         bool filtering) {
+    // Transform matrices
+    static const mat4 mtxFlipH(
+        -1, 0, 0, 0,
+        0, 1, 0, 0,
+        0, 0, 1, 0,
+        1, 0, 0, 1
+    );
+    static const mat4 mtxFlipV(
+        1, 0, 0, 0,
+        0, -1, 0, 0,
+        0, 0, 1, 0,
+        0, 1, 0, 1
+    );
+    static const mat4 mtxRot90(
+        0, 1, 0, 0,
+        -1, 0, 0, 0,
+        0, 0, 1, 0,
+        1, 0, 0, 1
+    );
 
-    float xform[16];
-    for (int i = 0; i < 16; i++) {
-        xform[i] = mtxIdentity[i];
-    }
+    mat4 xform;
     if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_H) {
-        float result[16];
-        mtxMul(result, xform, mtxFlipH);
-        for (int i = 0; i < 16; i++) {
-            xform[i] = result[i];
-        }
+        xform *= mtxFlipH;
     }
     if (transform & NATIVE_WINDOW_TRANSFORM_FLIP_V) {
-        float result[16];
-        mtxMul(result, xform, mtxFlipV);
-        for (int i = 0; i < 16; i++) {
-            xform[i] = result[i];
-        }
+        xform *= mtxFlipV;
     }
     if (transform & NATIVE_WINDOW_TRANSFORM_ROT_90) {
-        float result[16];
-        mtxMul(result, xform, mtxRot90);
-        for (int i = 0; i < 16; i++) {
-            xform[i] = result[i];
-        }
+        xform *= mtxRot90;
     }
 
-    float mtxBeforeFlipV[16];
     if (!cropRect.isEmpty()) {
         float tx = 0.0f, ty = 0.0f, sx = 1.0f, sy = 1.0f;
         float bufferWidth = buf->getWidth();
@@ -893,25 +853,63 @@
             sy = (float(cropRect.height()) - (2.0f * shrinkAmount)) /
                     bufferHeight;
         }
-        float crop[16] = {
+
+        mat4 crop(
             sx, 0, 0, 0,
             0, sy, 0, 0,
             0, 0, 1, 0,
-            tx, ty, 0, 1,
-        };
-
-        mtxMul(mtxBeforeFlipV, crop, xform);
-    } else {
-        for (int i = 0; i < 16; i++) {
-            mtxBeforeFlipV[i] = xform[i];
-        }
+            tx, ty, 0, 1
+        );
+        xform = crop * xform;
     }
 
     // SurfaceFlinger expects the top of its window textures to be at a Y
     // coordinate of 0, so GLConsumer must behave the same way.  We don't
     // want to expose this to applications, however, so we must add an
     // additional vertical flip to the transform after all the other transforms.
-    mtxMul(outTransform, mtxFlipV, mtxBeforeFlipV);
+    xform = mtxFlipV * xform;
+
+    memcpy(outTransform, xform.asArray(), sizeof(xform));
+}
+
+Rect GLConsumer::scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight) {
+    Rect outCrop = crop;
+
+    uint32_t newWidth = static_cast<uint32_t>(crop.width());
+    uint32_t newHeight = static_cast<uint32_t>(crop.height());
+
+    if (newWidth * bufferHeight > newHeight * bufferWidth) {
+        newWidth = newHeight * bufferWidth / bufferHeight;
+        ALOGV("too wide: newWidth = %d", newWidth);
+    } else if (newWidth * bufferHeight < newHeight * bufferWidth) {
+        newHeight = newWidth * bufferHeight / bufferWidth;
+        ALOGV("too tall: newHeight = %d", newHeight);
+    }
+
+    uint32_t currentWidth = static_cast<uint32_t>(crop.width());
+    uint32_t currentHeight = static_cast<uint32_t>(crop.height());
+
+    // The crop is too wide
+    if (newWidth < currentWidth) {
+        uint32_t dw = currentWidth - newWidth;
+        auto halfdw = dw / 2;
+        outCrop.left += halfdw;
+        // Not halfdw because it would subtract 1 too few when dw is odd
+        outCrop.right -= (dw - halfdw);
+        // The crop is too tall
+    } else if (newHeight < currentHeight) {
+        uint32_t dh = currentHeight - newHeight;
+        auto halfdh = dh / 2;
+        outCrop.top += halfdh;
+        // Not halfdh because it would subtract 1 too few when dh is odd
+        outCrop.bottom -= (dh - halfdh);
+    }
+
+    ALOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
+            outCrop.left, outCrop.top,
+            outCrop.right,outCrop.bottom);
+
+    return outCrop;
 }
 
 nsecs_t GLConsumer::getTimestamp() {
@@ -945,45 +943,9 @@
 
 Rect GLConsumer::getCurrentCrop() const {
     Mutex::Autolock lock(mMutex);
-
-    Rect outCrop = mCurrentCrop;
-    if (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP) {
-        uint32_t newWidth = static_cast<uint32_t>(mCurrentCrop.width());
-        uint32_t newHeight = static_cast<uint32_t>(mCurrentCrop.height());
-
-        if (newWidth * mDefaultHeight > newHeight * mDefaultWidth) {
-            newWidth = newHeight * mDefaultWidth / mDefaultHeight;
-            GLC_LOGV("too wide: newWidth = %d", newWidth);
-        } else if (newWidth * mDefaultHeight < newHeight * mDefaultWidth) {
-            newHeight = newWidth * mDefaultHeight / mDefaultWidth;
-            GLC_LOGV("too tall: newHeight = %d", newHeight);
-        }
-
-        uint32_t currentWidth = static_cast<uint32_t>(mCurrentCrop.width());
-        uint32_t currentHeight = static_cast<uint32_t>(mCurrentCrop.height());
-
-        // The crop is too wide
-        if (newWidth < currentWidth) {
-            uint32_t dw = currentWidth - newWidth;
-            auto halfdw = dw / 2;
-            outCrop.left += halfdw;
-            // Not halfdw because it would subtract 1 too few when dw is odd
-            outCrop.right -= (dw - halfdw);
-        // The crop is too tall
-        } else if (newHeight < currentHeight) {
-            uint32_t dh = currentHeight - newHeight;
-            auto halfdh = dh / 2;
-            outCrop.top += halfdh;
-            // Not halfdh because it would subtract 1 too few when dh is odd
-            outCrop.bottom -= (dh - halfdh);
-        }
-
-        GLC_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
-            outCrop.left, outCrop.top,
-            outCrop.right,outCrop.bottom);
-    }
-
-    return outCrop;
+    return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
+        ? scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
+        : mCurrentCrop;
 }
 
 uint32_t GLConsumer::getCurrentTransform() const {
@@ -1006,11 +968,6 @@
     return mCurrentFenceTime;
 }
 
-status_t GLConsumer::doGLFenceWait() const {
-    Mutex::Autolock lock(mMutex);
-    return doGLFenceWaitLocked();
-}
-
 status_t GLConsumer::doGLFenceWaitLocked() const {
 
     EGLDisplay dpy = eglGetCurrentDisplay();
@@ -1086,61 +1043,8 @@
     ConsumerBase::abandonLocked();
 }
 
-void GLConsumer::setName(const String8& name) {
-    Mutex::Autolock _l(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setName: GLConsumer is abandoned!");
-        return;
-    }
-    mName = name;
-    mConsumer->setConsumerName(name);
-}
-
-status_t GLConsumer::setDefaultBufferFormat(PixelFormat defaultFormat) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setDefaultBufferFormat: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->setDefaultBufferFormat(defaultFormat);
-}
-
-status_t GLConsumer::setDefaultBufferDataSpace(
-        android_dataspace defaultDataSpace) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setDefaultBufferDataSpace: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->setDefaultBufferDataSpace(defaultDataSpace);
-}
-
 status_t GLConsumer::setConsumerUsageBits(uint64_t usage) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setConsumerUsageBits: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-    usage |= DEFAULT_USAGE_FLAGS;
-    return mConsumer->setConsumerUsageBits(usage);
-}
-
-status_t GLConsumer::setTransformHint(uint32_t hint) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setTransformHint: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->setTransformHint(hint);
-}
-
-status_t GLConsumer::setMaxAcquiredBufferCount(int maxAcquiredBuffers) {
-    Mutex::Autolock lock(mMutex);
-    if (mAbandoned) {
-        GLC_LOGE("setMaxAcquiredBufferCount: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-    return mConsumer->setMaxAcquiredBufferCount(maxAcquiredBuffers);
+    return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
 }
 
 void GLConsumer::dumpLocked(String8& result, const char* prefix) const
@@ -1155,28 +1059,6 @@
     ConsumerBase::dumpLocked(result, prefix);
 }
 
-static void mtxMul(float out[16], const float a[16], const float b[16]) {
-    out[0] = a[0]*b[0] + a[4]*b[1] + a[8]*b[2] + a[12]*b[3];
-    out[1] = a[1]*b[0] + a[5]*b[1] + a[9]*b[2] + a[13]*b[3];
-    out[2] = a[2]*b[0] + a[6]*b[1] + a[10]*b[2] + a[14]*b[3];
-    out[3] = a[3]*b[0] + a[7]*b[1] + a[11]*b[2] + a[15]*b[3];
-
-    out[4] = a[0]*b[4] + a[4]*b[5] + a[8]*b[6] + a[12]*b[7];
-    out[5] = a[1]*b[4] + a[5]*b[5] + a[9]*b[6] + a[13]*b[7];
-    out[6] = a[2]*b[4] + a[6]*b[5] + a[10]*b[6] + a[14]*b[7];
-    out[7] = a[3]*b[4] + a[7]*b[5] + a[11]*b[6] + a[15]*b[7];
-
-    out[8] = a[0]*b[8] + a[4]*b[9] + a[8]*b[10] + a[12]*b[11];
-    out[9] = a[1]*b[8] + a[5]*b[9] + a[9]*b[10] + a[13]*b[11];
-    out[10] = a[2]*b[8] + a[6]*b[9] + a[10]*b[10] + a[14]*b[11];
-    out[11] = a[3]*b[8] + a[7]*b[9] + a[11]*b[10] + a[15]*b[11];
-
-    out[12] = a[0]*b[12] + a[4]*b[13] + a[8]*b[14] + a[12]*b[15];
-    out[13] = a[1]*b[12] + a[5]*b[13] + a[9]*b[14] + a[13]*b[15];
-    out[14] = a[2]*b[12] + a[6]*b[13] + a[10]*b[14] + a[14]*b[15];
-    out[15] = a[3]*b[12] + a[7]*b[13] + a[11]*b[14] + a[15]*b[15];
-}
-
 GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) :
     mGraphicBuffer(graphicBuffer),
     mEglImage(EGL_NO_IMAGE_KHR),
diff --git a/libs/gui/include/gui/BufferItemConsumer.h b/libs/gui/include/gui/BufferItemConsumer.h
index d9c5775..a905610 100644
--- a/libs/gui/include/gui/BufferItemConsumer.h
+++ b/libs/gui/include/gui/BufferItemConsumer.h
@@ -57,10 +57,6 @@
 
     ~BufferItemConsumer() override;
 
-    // set the name of the BufferItemConsumer that will be used to identify it in
-    // log messages.
-    void setName(const String8& name);
-
     // setBufferFreedListener sets the listener object that will be notified
     // when an old buffer is being freed.
     void setBufferFreedListener(const wp<BufferFreedListener>& listener);
diff --git a/libs/gui/include/gui/ConsumerBase.h b/libs/gui/include/gui/ConsumerBase.h
index 4a86021..366ced3 100644
--- a/libs/gui/include/gui/ConsumerBase.h
+++ b/libs/gui/include/gui/ConsumerBase.h
@@ -89,6 +89,18 @@
     // See IGraphicBufferConsumer::setDefaultBufferDataSpace
     status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
 
+    // See IGraphicBufferConsumer::setConsumerUsageBits
+    status_t setConsumerUsageBits(uint64_t usage);
+
+    // See IGraphicBufferConsumer::setTransformHint
+    status_t setTransformHint(uint32_t hint);
+
+    // See IGraphicBufferConsumer::setMaxAcquiredBufferCount
+    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
+
+    // See IGraphicBufferConsumer::getSidebandStream
+    sp<NativeHandle> getSidebandStream() const;
+
     // See IGraphicBufferConsumer::getOccupancyHistory
     status_t getOccupancyHistory(bool forceFlush,
             std::vector<OccupancyTracker::Segment>* outHistory);
diff --git a/libs/gui/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h
index 58602bf..d375611 100644
--- a/libs/gui/include/gui/CpuConsumer.h
+++ b/libs/gui/include/gui/CpuConsumer.h
@@ -94,12 +94,6 @@
     CpuConsumer(const sp<IGraphicBufferConsumer>& bq,
             size_t maxLockedBuffers, bool controlledByApp = false);
 
-    virtual ~CpuConsumer();
-
-    // set the name of the CpuConsumer that will be used to identify it in
-    // log messages.
-    void setName(const String8& name);
-
     // Gets the next graphics buffer from the producer and locks it for CPU use,
     // filling out the passed-in locked buffer structure with the native pointer
     // and metadata. Returns BAD_VALUE if no new buffer is available, and
@@ -119,31 +113,39 @@
 
   private:
     // Maximum number of buffers that can be locked at a time
-    size_t mMaxLockedBuffers;
-
-    status_t releaseAcquiredBufferLocked(size_t lockedIdx);
-
-    virtual void freeBufferLocked(int slotIndex);
+    const size_t mMaxLockedBuffers;
 
     // Tracking for buffers acquired by the user
     struct AcquiredBuffer {
+        static constexpr uintptr_t kUnusedId = 0;
+
         // Need to track the original mSlot index and the buffer itself because
         // the mSlot entry may be freed/reused before the acquired buffer is
         // released.
         int mSlot;
         sp<GraphicBuffer> mGraphicBuffer;
-        void *mBufferPointer;
+        uintptr_t mLockedBufferId;
 
         AcquiredBuffer() :
                 mSlot(BufferQueue::INVALID_BUFFER_SLOT),
-                mBufferPointer(NULL) {
+                mLockedBufferId(kUnusedId) {
+        }
+
+        void reset() {
+            mSlot = BufferQueue::INVALID_BUFFER_SLOT;
+            mGraphicBuffer.clear();
+            mLockedBufferId = kUnusedId;
         }
     };
+
+    size_t findAcquiredBufferLocked(uintptr_t id) const;
+
+    status_t lockBufferItem(const BufferItem& item, LockedBuffer* outBuffer) const;
+
     Vector<AcquiredBuffer> mAcquiredBuffers;
 
     // Count of currently locked buffers
     size_t mCurrentLockedBuffers;
-
 };
 
 } // namespace android
diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
index 75f2cca..71ed3bf 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -138,6 +138,10 @@
             const sp<GraphicBuffer>& buf, const Rect& cropRect,
             uint32_t transform, bool filtering);
 
+    // Scale the crop down horizontally or vertically such that it has the
+    // same aspect ratio as the buffer does.
+    static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight);
+
     // getTimestamp retrieves the timestamp associated with the texture image
     // set by the most recent call to updateTexImage.
     //
@@ -197,22 +201,9 @@
     // buffer is ready to be read from.
     std::shared_ptr<FenceTime> getCurrentFenceTime() const;
 
-    // doGLFenceWait inserts a wait command into the OpenGL ES command stream
-    // to ensure that it is safe for future OpenGL ES commands to access the
-    // current texture buffer.
-    status_t doGLFenceWait() const;
-
-    // set the name of the GLConsumer that will be used to identify it in
-    // log messages.
-    void setName(const String8& name);
-
-    // These functions call the corresponding BufferQueue implementation
-    // so the refactoring can proceed smoothly
-    status_t setDefaultBufferFormat(PixelFormat defaultFormat);
-    status_t setDefaultBufferDataSpace(android_dataspace defaultDataSpace);
+    // setConsumerUsageBits overrides the ConsumerBase method to OR
+    // DEFAULT_USAGE_FLAGS to usage.
     status_t setConsumerUsageBits(uint64_t usage);
-    status_t setTransformHint(uint32_t hint);
-    status_t setMaxAcquiredBufferCount(int maxAcquiredBuffers);
 
     // detachFromContext detaches the GLConsumer from the calling thread's
     // current OpenGL ES context.  This context must be the same as the context
@@ -267,8 +258,6 @@
         return releaseBufferLocked(slot, graphicBuffer, mEglDisplay, eglFence);
     }
 
-    static bool isExternalFormat(PixelFormat format);
-
     struct PendingRelease {
         PendingRelease() : isPending(false), currentTexture(-1),
                 graphicBuffer(), display(nullptr), fence(nullptr) {}
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 588e541..36be7d9 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -33,6 +33,7 @@
 #include <utils/Mutex.h>
 #include <utils/Condition.h>
 
+#include <thread>
 #include <vector>
 #define CPU_CONSUMER_TEST_FORMAT_RAW 0
 #define CPU_CONSUMER_TEST_FORMAT_Y8 0
@@ -681,6 +682,70 @@
     }
 }
 
+TEST_P(CpuConsumerTest, FromCpuInvalid) {
+    status_t err = mCC->lockNextBuffer(nullptr);
+    ASSERT_EQ(BAD_VALUE, err) << "lockNextBuffer did not fail";
+
+    CpuConsumer::LockedBuffer b;
+    err = mCC->unlockBuffer(b);
+    ASSERT_EQ(BAD_VALUE, err) << "unlockBuffer did not fail";
+}
+
+TEST_P(CpuConsumerTest, FromCpuMultiThread) {
+    CpuConsumerTestParams params = GetParam();
+    ASSERT_NO_FATAL_FAILURE(configureANW(mANW, params, params.maxLockedBuffers + 1));
+
+    for (int i = 0; i < 10; i++) {
+        std::atomic<int> threadReadyCount(0);
+        auto lockAndUnlock = [&]() {
+            threadReadyCount++;
+            // busy wait
+            while (threadReadyCount < params.maxLockedBuffers + 1);
+
+            CpuConsumer::LockedBuffer b;
+            status_t err = mCC->lockNextBuffer(&b);
+            if (err == NO_ERROR) {
+                usleep(1000);
+                err = mCC->unlockBuffer(b);
+                ASSERT_NO_ERROR(err, "Could not unlock buffer: ");
+            } else if (err == NOT_ENOUGH_DATA) {
+                // there are params.maxLockedBuffers+1 threads so one of the
+                // threads might get this error
+            } else {
+                FAIL() << "Could not lock buffer";
+            }
+        };
+
+        // produce buffers
+        for (int j = 0; j < params.maxLockedBuffers + 1; j++) {
+            const int64_t time = 1234L;
+            uint32_t stride;
+            ASSERT_NO_FATAL_FAILURE(produceOneFrame(mANW, params, time, &stride));
+        }
+
+        // spawn threads
+        std::vector<std::thread> threads;
+        for (int j = 0; j < params.maxLockedBuffers + 1; j++) {
+            threads.push_back(std::thread(lockAndUnlock));
+        }
+
+        // join threads
+        for (auto& thread : threads) {
+            thread.join();
+        }
+
+        // we produced N+1 buffers, but the threads might only consume N
+        CpuConsumer::LockedBuffer b;
+        if (mCC->lockNextBuffer(&b) == NO_ERROR) {
+            mCC->unlockBuffer(b);
+        }
+
+        if (HasFatalFailure()) {
+            break;
+        }
+    }
+}
+
 CpuConsumerTestParams y8TestSets[] = {
     { 512,   512, 1, HAL_PIXEL_FORMAT_Y8},
     { 512,   512, 3, HAL_PIXEL_FORMAT_Y8},
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index b8901bd..5fe8d8b 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -99,34 +99,34 @@
 
 // --- InputChannel ---
 
-InputChannel::InputChannel(const String8& name, int fd) :
+InputChannel::InputChannel(const std::string& name, int fd) :
         mName(name), mFd(fd) {
 #if DEBUG_CHANNEL_LIFECYCLE
     ALOGD("Input channel constructed: name='%s', fd=%d",
-            mName.string(), fd);
+            mName.c_str(), fd);
 #endif
 
     int result = fcntl(mFd, F_SETFL, O_NONBLOCK);
     LOG_ALWAYS_FATAL_IF(result != 0, "channel '%s' ~ Could not make socket "
-            "non-blocking.  errno=%d", mName.string(), errno);
+            "non-blocking.  errno=%d", mName.c_str(), errno);
 }
 
 InputChannel::~InputChannel() {
 #if DEBUG_CHANNEL_LIFECYCLE
     ALOGD("Input channel destroyed: name='%s', fd=%d",
-            mName.string(), mFd);
+            mName.c_str(), mFd);
 #endif
 
     ::close(mFd);
 }
 
-status_t InputChannel::openInputChannelPair(const String8& name,
+status_t InputChannel::openInputChannelPair(const std::string& name,
         sp<InputChannel>& outServerChannel, sp<InputChannel>& outClientChannel) {
     int sockets[2];
     if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, sockets)) {
         status_t result = -errno;
         ALOGE("channel '%s' ~ Could not create socket pair.  errno=%d",
-                name.string(), errno);
+                name.c_str(), errno);
         outServerChannel.clear();
         outClientChannel.clear();
         return result;
@@ -138,12 +138,12 @@
     setsockopt(sockets[1], SOL_SOCKET, SO_SNDBUF, &bufferSize, sizeof(bufferSize));
     setsockopt(sockets[1], SOL_SOCKET, SO_RCVBUF, &bufferSize, sizeof(bufferSize));
 
-    String8 serverChannelName = name;
-    serverChannelName.append(" (server)");
+    std::string serverChannelName = name;
+    serverChannelName += " (server)";
     outServerChannel = new InputChannel(serverChannelName, sockets[0]);
 
-    String8 clientChannelName = name;
-    clientChannelName.append(" (client)");
+    std::string clientChannelName = name;
+    clientChannelName += " (client)";
     outClientChannel = new InputChannel(clientChannelName, sockets[1]);
     return OK;
 }
@@ -158,7 +158,7 @@
     if (nWrite < 0) {
         int error = errno;
 #if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.string(),
+        ALOGD("channel '%s' ~ error sending message of type %d, errno=%d", mName.c_str(),
                 msg->header.type, error);
 #endif
         if (error == EAGAIN || error == EWOULDBLOCK) {
@@ -173,13 +173,13 @@
     if (size_t(nWrite) != msgLength) {
 #if DEBUG_CHANNEL_MESSAGES
         ALOGD("channel '%s' ~ error sending message type %d, send was incomplete",
-                mName.string(), msg->header.type);
+                mName.c_str(), msg->header.type);
 #endif
         return DEAD_OBJECT;
     }
 
 #if DEBUG_CHANNEL_MESSAGES
-    ALOGD("channel '%s' ~ sent message of type %d", mName.string(), msg->header.type);
+    ALOGD("channel '%s' ~ sent message of type %d", mName.c_str(), msg->header.type);
 #endif
     return OK;
 }
@@ -193,7 +193,7 @@
     if (nRead < 0) {
         int error = errno;
 #if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.string(), errno);
+        ALOGD("channel '%s' ~ receive message failed, errno=%d", mName.c_str(), errno);
 #endif
         if (error == EAGAIN || error == EWOULDBLOCK) {
             return WOULD_BLOCK;
@@ -206,20 +206,20 @@
 
     if (nRead == 0) { // check for EOF
 #if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.string());
+        ALOGD("channel '%s' ~ receive message failed because peer was closed", mName.c_str());
 #endif
         return DEAD_OBJECT;
     }
 
     if (!msg->isValid(nRead)) {
 #if DEBUG_CHANNEL_MESSAGES
-        ALOGD("channel '%s' ~ received invalid message", mName.string());
+        ALOGD("channel '%s' ~ received invalid message", mName.c_str());
 #endif
         return BAD_VALUE;
     }
 
 #if DEBUG_CHANNEL_MESSAGES
-    ALOGD("channel '%s' ~ received message of type %d", mName.string(), msg->header.type);
+    ALOGD("channel '%s' ~ received message of type %d", mName.c_str(), msg->header.type);
 #endif
     return OK;
 }
@@ -255,7 +255,7 @@
     ALOGD("channel '%s' publisher ~ publishKeyEvent: seq=%u, deviceId=%d, source=0x%x, "
             "action=0x%x, flags=0x%x, keyCode=%d, scanCode=%d, metaState=0x%x, repeatCount=%d,"
             "downTime=%" PRId64 ", eventTime=%" PRId64,
-            mChannel->getName().string(), seq,
+            mChannel->getName().c_str(), seq,
             deviceId, source, action, flags, keyCode, scanCode, metaState, repeatCount,
             downTime, eventTime);
 #endif
@@ -307,7 +307,7 @@
             "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, "
             "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "
             "pointerCount=%" PRIu32,
-            mChannel->getName().string(), seq,
+            mChannel->getName().c_str(), seq,
             deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState,
             xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
 #endif
@@ -319,7 +319,7 @@
 
     if (pointerCount > MAX_POINTERS || pointerCount < 1) {
         ALOGE("channel '%s' publisher ~ Invalid number of pointers provided: %" PRIu32 ".",
-                mChannel->getName().string(), pointerCount);
+                mChannel->getName().c_str(), pointerCount);
         return BAD_VALUE;
     }
 
@@ -352,7 +352,7 @@
 status_t InputPublisher::receiveFinishedSignal(uint32_t* outSeq, bool* outHandled) {
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' publisher ~ receiveFinishedSignal",
-            mChannel->getName().string());
+            mChannel->getName().c_str());
 #endif
 
     InputMessage msg;
@@ -364,7 +364,7 @@
     }
     if (msg.header.type != InputMessage::TYPE_FINISHED) {
         ALOGE("channel '%s' publisher ~ Received unexpected message of type %d from consumer",
-                mChannel->getName().string(), msg.header.type);
+                mChannel->getName().c_str(), msg.header.type);
         return UNKNOWN_ERROR;
     }
     *outSeq = msg.body.finished.seq;
@@ -402,7 +402,7 @@
         int32_t* displayId) {
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64,
-            mChannel->getName().string(), consumeBatches ? "true" : "false", frameTime);
+            mChannel->getName().c_str(), consumeBatches ? "true" : "false", frameTime);
 #endif
 
     *outSeq = 0;
@@ -426,7 +426,7 @@
                     if (*outEvent) {
 #if DEBUG_TRANSPORT_ACTIONS
                         ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
-                                mChannel->getName().string(), *outSeq);
+                                mChannel->getName().c_str(), *outSeq);
 #endif
                         break;
                     }
@@ -445,7 +445,7 @@
             *outEvent = keyEvent;
 #if DEBUG_TRANSPORT_ACTIONS
             ALOGD("channel '%s' consumer ~ consumed key event, seq=%u",
-                    mChannel->getName().string(), *outSeq);
+                    mChannel->getName().c_str(), *outSeq);
 #endif
             break;
         }
@@ -458,7 +458,7 @@
                     batch.samples.push(mMsg);
 #if DEBUG_TRANSPORT_ACTIONS
                     ALOGD("channel '%s' consumer ~ appended to batch event",
-                            mChannel->getName().string());
+                            mChannel->getName().c_str());
 #endif
                     break;
                 } else {
@@ -474,7 +474,7 @@
 #if DEBUG_TRANSPORT_ACTIONS
                     ALOGD("channel '%s' consumer ~ consumed batch event and "
                             "deferred current event, seq=%u",
-                            mChannel->getName().string(), *outSeq);
+                            mChannel->getName().c_str(), *outSeq);
 #endif
                     break;
                 }
@@ -488,7 +488,7 @@
                 batch.samples.push(mMsg);
 #if DEBUG_TRANSPORT_ACTIONS
                 ALOGD("channel '%s' consumer ~ started batch event",
-                        mChannel->getName().string());
+                        mChannel->getName().c_str());
 #endif
                 break;
             }
@@ -503,14 +503,14 @@
             *displayId = mMsg.body.motion.displayId;
 #if DEBUG_TRANSPORT_ACTIONS
             ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
-                    mChannel->getName().string(), *outSeq);
+                    mChannel->getName().c_str(), *outSeq);
 #endif
             break;
         }
 
         default:
             ALOGE("channel '%s' consumer ~ Received unexpected message of type %d",
-                    mChannel->getName().string(), mMsg.header.type);
+                    mChannel->getName().c_str(), mMsg.header.type);
             return UNKNOWN_ERROR;
         }
     }
@@ -828,7 +828,7 @@
 status_t InputConsumer::sendFinishedSignal(uint32_t seq, bool handled) {
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' consumer ~ sendFinishedSignal: seq=%u, handled=%s",
-            mChannel->getName().string(), seq, handled ? "true" : "false");
+            mChannel->getName().c_str(), seq, handled ? "true" : "false");
 #endif
 
     if (!seq) {
diff --git a/libs/input/tests/InputChannel_test.cpp b/libs/input/tests/InputChannel_test.cpp
index e71ebe2..96c165c 100644
--- a/libs/input/tests/InputChannel_test.cpp
+++ b/libs/input/tests/InputChannel_test.cpp
@@ -41,9 +41,9 @@
     // of a pipe and to check for EPIPE on the other end after the channel is destroyed.
     Pipe pipe;
 
-    sp<InputChannel> inputChannel = new InputChannel(String8("channel name"), pipe.sendFd);
+    sp<InputChannel> inputChannel = new InputChannel("channel name", pipe.sendFd);
 
-    EXPECT_STREQ("channel name", inputChannel->getName().string())
+    EXPECT_STREQ("channel name", inputChannel->getName().c_str())
             << "channel should have provided name";
     EXPECT_EQ(pipe.sendFd, inputChannel->getFd())
             << "channel should have provided fd";
@@ -60,16 +60,16 @@
 TEST_F(InputChannelTest, OpenInputChannelPair_ReturnsAPairOfConnectedChannels) {
     sp<InputChannel> serverChannel, clientChannel;
 
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
+    status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
 
     ASSERT_EQ(OK, result)
             << "should have successfully opened a channel pair";
 
     // Name
-    EXPECT_STREQ("channel name (server)", serverChannel->getName().string())
+    EXPECT_STREQ("channel name (server)", serverChannel->getName().c_str())
             << "server channel should have suffixed name";
-    EXPECT_STREQ("channel name (client)", clientChannel->getName().string())
+    EXPECT_STREQ("channel name (client)", clientChannel->getName().c_str())
             << "client channel should have suffixed name";
 
     // Server->Client communication
@@ -111,7 +111,7 @@
 TEST_F(InputChannelTest, ReceiveSignal_WhenNoSignalPresent_ReturnsAnError) {
     sp<InputChannel> serverChannel, clientChannel;
 
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
+    status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
 
     ASSERT_EQ(OK, result)
@@ -125,7 +125,7 @@
 TEST_F(InputChannelTest, ReceiveSignal_WhenPeerClosed_ReturnsAnError) {
     sp<InputChannel> serverChannel, clientChannel;
 
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
+    status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
 
     ASSERT_EQ(OK, result)
@@ -141,7 +141,7 @@
 TEST_F(InputChannelTest, SendSignal_WhenPeerClosed_ReturnsAnError) {
     sp<InputChannel> serverChannel, clientChannel;
 
-    status_t result = InputChannel::openInputChannelPair(String8("channel name"),
+    status_t result = InputChannel::openInputChannelPair("channel name",
             serverChannel, clientChannel);
 
     ASSERT_EQ(OK, result)
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index f86f876..c532241 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -36,7 +36,7 @@
     PreallocatedInputEventFactory mEventFactory;
 
     virtual void SetUp() {
-        status_t result = InputChannel::openInputChannelPair(String8("channel name"),
+        status_t result = InputChannel::openInputChannelPair("channel name",
                 serverChannel, clientChannel);
 
         mPublisher = new InputPublisher(serverChannel);
diff --git a/libs/nativewindow/Android.bp b/libs/nativewindow/Android.bp
index 64eb110..29555fd 100644
--- a/libs/nativewindow/Android.bp
+++ b/libs/nativewindow/Android.bp
@@ -30,7 +30,10 @@
 
 cc_library {
     name: "libnativewindow",
-    export_include_dirs: ["include"],
+    export_include_dirs: [
+        "include",
+        "include-private",
+    ],
 
     clang: true,
 
@@ -44,6 +47,8 @@
         "-std=c++1z"
     ],
 
+    version_script: "libnativewindow.map.txt",
+
     srcs: [
         "AHardwareBuffer.cpp",
         "ANativeWindow.cpp",
diff --git a/libs/nativewindow/include/private/android/AHardwareBufferHelpers.h b/libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
similarity index 100%
rename from libs/nativewindow/include/private/android/AHardwareBufferHelpers.h
rename to libs/nativewindow/include-private/private/android/AHardwareBufferHelpers.h
diff --git a/libs/nativewindow/libnativewindow.map.txt b/libs/nativewindow/libnativewindow.map.txt
index 58045be..105d01b 100644
--- a/libs/nativewindow/libnativewindow.map.txt
+++ b/libs/nativewindow/libnativewindow.map.txt
@@ -3,13 +3,11 @@
     AHardwareBuffer_acquire;
     AHardwareBuffer_allocate;
     AHardwareBuffer_describe;
-    AHardwareBuffer_fromHardwareBuffer;
     AHardwareBuffer_getNativeHandle; # vndk
     AHardwareBuffer_lock;
     AHardwareBuffer_recvHandleFromUnixSocket;
     AHardwareBuffer_release;
     AHardwareBuffer_sendHandleToUnixSocket;
-    AHardwareBuffer_toHardwareBuffer;
     AHardwareBuffer_unlock;
     ANativeWindowBuffer_getHardwareBuffer; # vndk
     ANativeWindow_OemStorageGet; # vndk
@@ -17,8 +15,6 @@
     ANativeWindow_acquire;
     ANativeWindow_cancelBuffer; # vndk
     ANativeWindow_dequeueBuffer; # vndk
-    ANativeWindow_fromSurface;
-    ANativeWindow_fromSurfaceTexture;
     ANativeWindow_getFormat;
     ANativeWindow_getHeight;
     ANativeWindow_getWidth;
@@ -42,3 +38,17 @@
   local:
     *;
 };
+
+LIBNATIVEWINDOW_PLATFORM {
+  global:
+    extern "C++" {
+      android::AHardwareBuffer_isValidPixelFormat*;
+      android::AHardwareBuffer_convertFromPixelFormat*;
+      android::AHardwareBuffer_convertToPixelFormat*;
+      android::AHardwareBuffer_convertFromGrallocUsageBits*;
+      android::AHardwareBuffer_convertToGrallocUsageBits*;
+      android::AHardwareBuffer_to_GraphicBuffer*;
+      android::AHardwareBuffer_to_ANativeWindowBuffer*;
+      android::AHardwareBuffer_from_GraphicBuffer*;
+    };
+} LIBNATIVEWINDOW;
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 102964f..abe856e 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -95,6 +95,7 @@
     ],
 
     header_libs: [
+        "libbase_headers",
         "libnativebase_headers",
         "libhardware_headers",
     ],
@@ -107,6 +108,7 @@
     ],
 
     export_header_lib_headers: [
+        "libbase_headers",
         "libnativebase_headers",
         "libhardware_headers",
     ],
diff --git a/libs/ui/Fence.cpp b/libs/ui/Fence.cpp
index b67f4d9..ff53aa8 100644
--- a/libs/ui/Fence.cpp
+++ b/libs/ui/Fence.cpp
@@ -37,18 +37,12 @@
 
 const sp<Fence> Fence::NO_FENCE = sp<Fence>(new Fence);
 
-Fence::Fence() :
-    mFenceFd(-1) {
-}
-
 Fence::Fence(int fenceFd) :
     mFenceFd(fenceFd) {
 }
 
-Fence::~Fence() {
-    if (mFenceFd != -1) {
-        close(mFenceFd);
-    }
+Fence::Fence(base::unique_fd fenceFd) :
+    mFenceFd(std::move(fenceFd)) {
 }
 
 status_t Fence::wait(int timeout) {
@@ -68,7 +62,7 @@
     int warningTimeout = 3000;
     int err = sync_wait(mFenceFd, warningTimeout);
     if (err < 0 && errno == ETIME) {
-        ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd,
+        ALOGE("%s: fence %d didn't signal in %u ms", logname, mFenceFd.get(),
                 warningTimeout);
         err = sync_wait(mFenceFd, TIMEOUT_NEVER);
     }
@@ -94,7 +88,7 @@
     if (result == -1) {
         status_t err = -errno;
         ALOGE("merge: sync_merge(\"%s\", %d, %d) returned an error: %s (%d)",
-                name, f1->mFenceFd, f2->mFenceFd,
+                name, f1->mFenceFd.get(), f2->mFenceFd.get(),
                 strerror(-err), err);
         return NO_FENCE;
     }
@@ -117,7 +111,7 @@
 
     struct sync_fence_info_data* finfo = sync_fence_info(mFenceFd);
     if (finfo == NULL) {
-        ALOGE("sync_fence_info returned NULL for fd %d", mFenceFd);
+        ALOGE("sync_fence_info returned NULL for fd %d", mFenceFd.get());
         return SIGNAL_TIME_INVALID;
     }
     if (finfo->status != 1) {
@@ -181,7 +175,7 @@
     }
 
     if (numFds) {
-        mFenceFd = *fds++;
+        mFenceFd.reset(*fds++);
         count--;
     }
 
diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h
index 37811bc..ec67fa9 100644
--- a/libs/ui/include/ui/Fence.h
+++ b/libs/ui/include/ui/Fence.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 
+#include <android-base/unique_fd.h>
 #include <utils/Flattenable.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
@@ -49,12 +50,13 @@
     // Construct a new Fence object with an invalid file descriptor.  This
     // should be done when the Fence object will be set up by unflattening
     // serialized data.
-    Fence();
+    Fence() = default;
 
     // Construct a new Fence object to manage a given fence file descriptor.
     // When the new Fence object is destructed the file descriptor will be
     // closed.
     explicit Fence(int fenceFd);
+    explicit Fence(base::unique_fd fenceFd);
 
     // Not copyable or movable.
     Fence(const Fence& rhs) = delete;
@@ -136,9 +138,9 @@
 private:
     // Only allow instantiation using ref counting.
     friend class LightRefBase<Fence>;
-    ~Fence();
+    ~Fence() = default;
 
-    int mFenceFd;
+    base::unique_fd mFenceFd;
 };
 
 }; // namespace android
diff --git a/libs/ui/include/ui/FloatRect.h b/libs/ui/include/ui/FloatRect.h
index 270675c..6a7479a 100644
--- a/libs/ui/include/ui/FloatRect.h
+++ b/libs/ui/include/ui/FloatRect.h
@@ -27,6 +27,17 @@
     float getWidth() const { return right - left; }
     float getHeight() const { return bottom - top; }
 
+    FloatRect intersect(const FloatRect& other) const {
+        return {
+            // Inline to avoid tromping on other min/max defines or adding a
+            // dependency on STL
+            (left > other.left) ? left : other.left,
+            (top > other.top) ? top : other.top,
+            (right < other.right) ? right : other.right,
+            (bottom < other.bottom) ? bottom : other.bottom
+        };
+    }
+
     float left = 0.0f;
     float top = 0.0f;
     float right = 0.0f;
diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
index b50e4ec..0bec0b7 100644
--- a/libs/ui/include/ui/Rect.h
+++ b/libs/ui/include/ui/Rect.h
@@ -69,6 +69,15 @@
         bottom = rb.y;
     }
 
+    inline explicit Rect(const FloatRect& floatRect) {
+        // Ideally we would use std::round, but we don't want to add an STL
+        // dependency here, so we use an approximation
+        left = static_cast<int32_t>(floatRect.left + 0.5f);
+        top = static_cast<int32_t>(floatRect.top + 0.5f);
+        right = static_cast<int32_t>(floatRect.right + 0.5f);
+        bottom = static_cast<int32_t>(floatRect.bottom + 0.5f);
+    }
+
     void makeInvalid();
 
     inline void clear() {
@@ -86,15 +95,18 @@
     }
 
     // rectangle's width
+    __attribute__((no_sanitize("signed-integer-overflow")))
     inline int32_t getWidth() const {
         return right - left;
     }
 
     // rectangle's height
+    __attribute__((no_sanitize("signed-integer-overflow")))
     inline int32_t getHeight() const {
         return bottom - top;
     }
 
+    __attribute__((no_sanitize("signed-integer-overflow")))
     inline Rect getBounds() const {
         return Rect(right - left, bottom - top);
     }
diff --git a/libs/vr/libbufferhub/buffer_hub-test.cpp b/libs/vr/libbufferhub/buffer_hub-test.cpp
index a5cf9ae..471ec7b 100644
--- a/libs/vr/libbufferhub/buffer_hub-test.cpp
+++ b/libs/vr/libbufferhub/buffer_hub-test.cpp
@@ -451,13 +451,19 @@
   EXPECT_EQ(0, c1->AcquireAsync(&metadata, &invalid_fence));
   EXPECT_EQ(0, c1->ReleaseAsync(&metadata, invalid_fence));
 
+  // Note that the next PDX call is on the producer channel, which may be
+  // executed before Release impulse gets executed by bufferhubd. Thus, here we
+  // need to wait until the releasd is confirmed before creating another
+  // consumer.
+  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
+  EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
+
   // Create another consumer immediately after the release, should not make the
-  // buffer un-released. This is guaranteed by IPC execution order in bufferhubd.
+  // buffer un-released.
   std::unique_ptr<BufferConsumer> c2 =
       BufferConsumer::Import(p->CreateConsumer());
   ASSERT_TRUE(c2.get() != nullptr);
 
-  EXPECT_LT(0, RETRY_EINTR(p->Poll(kPollTimeoutMs)));
   EXPECT_TRUE(IsBufferReleased(p->buffer_state()));
   EXPECT_EQ(0, p->GainAsync(&metadata, &invalid_fence));
   EXPECT_TRUE(IsBufferGained(p->buffer_state()));
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index a5cefd9..c75c67f 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -31,20 +31,6 @@
 
 namespace {
 
-// Polls an fd for the given events.
-Status<int> PollEvents(int fd, short events) {
-  const int kTimeoutMs = 0;
-  pollfd pfd{fd, events, 0};
-  const int count = RETRY_EINTR(poll(&pfd, 1, kTimeoutMs));
-  if (count < 0) {
-    return ErrorStatus(errno);
-  } else if (count == 0) {
-    return ErrorStatus(ETIMEDOUT);
-  } else {
-    return {pfd.revents};
-  }
-}
-
 std::pair<int32_t, int32_t> Unstuff(uint64_t value) {
   return {static_cast<int32_t>(value >> 32),
           static_cast<int32_t>(value & ((1ull << 32) - 1))};
@@ -670,27 +656,7 @@
     const std::shared_ptr<BufferConsumer>& buffer, size_t slot) {
   ALOGD_IF(TRACE, "ConsumerQueue::AddBuffer: queue_id=%d buffer_id=%d slot=%zu",
            id(), buffer->id(), slot);
-  auto status = BufferHubQueue::AddBuffer(buffer, slot);
-  if (!status)
-    return status;
-
-  // Check to see if the buffer is already signaled. This is necessary to catch
-  // cases where buffers are already available; epoll edge triggered mode does
-  // not fire until an edge transition when adding new buffers to the epoll
-  // set. Note that we only poll the fd events because HandleBufferEvent() takes
-  // care of checking the translated buffer events.
-  auto poll_status = PollEvents(buffer->event_fd(), POLLIN);
-  if (!poll_status && poll_status.error() != ETIMEDOUT) {
-    ALOGE("ConsumerQueue::AddBuffer: Failed to poll consumer buffer: %s",
-          poll_status.GetErrorMessage().c_str());
-    return poll_status.error_status();
-  }
-
-  // Update accounting if the buffer is available.
-  if (poll_status)
-    return HandleBufferEvent(slot, buffer->event_fd(), poll_status.get());
-  else
-    return {};
+  return BufferHubQueue::AddBuffer(buffer, slot);
 }
 
 Status<std::shared_ptr<BufferConsumer>> ConsumerQueue::Dequeue(
diff --git a/libs/vr/libbufferhubqueue/tests/Android.bp b/libs/vr/libbufferhubqueue/tests/Android.bp
index abeb719..5eba913 100644
--- a/libs/vr/libbufferhubqueue/tests/Android.bp
+++ b/libs/vr/libbufferhubqueue/tests/Android.bp
@@ -68,6 +68,8 @@
         "-DLOG_TAG=\"buffer_transport_benchmark\"",
         "-DTRACE=0",
         "-O2",
+        "-Wall",
+        "-Werror",
     ],
     name: "buffer_transport_benchmark",
     tags: ["optional"],
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index 3efa723..47a2734 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -329,7 +329,9 @@
 
   // Check that buffers are correctly imported on construction.
   EXPECT_EQ(consumer_queue_->capacity(), kBufferCount);
-  EXPECT_EQ(consumer_queue_->count(), 1U);
+  // Buffers are only imported, but their availability is not checked until
+  // first call to Dequeue().
+  EXPECT_EQ(consumer_queue_->count(), 0U);
 
   // Reclaim released/ignored buffers.
   EXPECT_EQ(producer_queue_->count(), kBufferCount - 1);
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp b/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
index 658b496..d4d25b0 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_transport_benchmark.cpp
@@ -34,7 +34,6 @@
 static const String16 kBinderService = String16("bufferTransport");
 static const uint32_t kBufferWidth = 100;
 static const uint32_t kBufferHeight = 1;
-static const uint32_t kBufferLayerCount = 1;
 static const uint32_t kBufferFormat = HAL_PIXEL_FORMAT_BLOB;
 static const uint64_t kBufferUsage =
     GRALLOC_USAGE_SW_READ_OFTEN | GRALLOC_USAGE_SW_WRITE_OFTEN;
@@ -75,10 +74,9 @@
  private:
   struct FrameListener : public ConsumerBase::FrameAvailableListener {
    public:
-    FrameListener(BufferTransportService* service,
+    FrameListener(BufferTransportService* /*service*/,
                   sp<BufferItemConsumer> buffer_item_consumer)
-        : service_(service),
-          buffer_item_consumer_(buffer_item_consumer) {}
+        : buffer_item_consumer_(buffer_item_consumer) {}
 
     void onFrameAvailable(const BufferItem& /*item*/) override {
       BufferItem buffer;
@@ -106,7 +104,6 @@
     }
 
    private:
-    BufferTransportService* service_ = nullptr;
     sp<BufferItemConsumer> buffer_item_consumer_;
   };
 
diff --git a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
index c21deb0..5c837e7 100644
--- a/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
+++ b/libs/vr/libdvr/tests/dvr_named_buffer-test.cpp
@@ -5,7 +5,6 @@
 #include <dvr/dvr_surface.h>
 #include <system/graphics.h>
 
-#include <base/logging.h>
 #include <gtest/gtest.h>
 
 namespace android {
@@ -22,7 +21,7 @@
 
   DvrBuffer* buffer2 = nullptr;
   int ret2 = dvrSetupGlobalBuffer(buffer_key, 10, 0, &buffer2);
-  ASSERT_EQ(0, ret1);
+  ASSERT_EQ(0, ret2);
   ASSERT_NE(nullptr, buffer2);
 
   AHardwareBuffer* hardware_buffer1 = nullptr;
@@ -159,7 +158,7 @@
     ASSERT_EQ(0, e3);
     ASSERT_NE(nullptr, buffer);
     // Verify that the buffer pointer is at least 16 byte aligned.
-    ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
+    ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
 
     uint64_t* data = static_cast<uint64_t*>(buffer);
     constexpr size_t num_values = size / sizeof(uint64_t);
@@ -192,7 +191,7 @@
     ASSERT_EQ(0, e3);
     ASSERT_NE(nullptr, buffer);
     // Verify that the buffer pointer is at least 16 byte aligned.
-    ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
+    ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
 
     uint64_t* data = static_cast<uint64_t*>(buffer);
     constexpr size_t num_values = size / sizeof(uint64_t);
@@ -233,7 +232,7 @@
   ASSERT_EQ(0, e3);
   ASSERT_NE(nullptr, buffer);
   // Verify that the buffer pointer is at least 16 byte aligned.
-  ASSERT_EQ(0, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
+  ASSERT_EQ(0U, reinterpret_cast<uintptr_t>(buffer) & (16 - 1));
 
   uint64_t* data = static_cast<uint64_t*>(buffer);
   constexpr size_t num_values = size / sizeof(uint64_t);
@@ -241,7 +240,7 @@
   for (size_t i = 0; i < num_values; ++i) {
     zero |= data[i];
   }
-  ASSERT_EQ(0, zero);
+  ASSERT_EQ(0U, zero);
 
   int32_t fence = -1;
   int e4 = AHardwareBuffer_unlock(hardware_buffer, &fence);
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 4e5833a..3c1edd1 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -79,6 +79,10 @@
 }
 
 egl_display_t* egl_display_t::get(EGLDisplay dpy) {
+    if (uintptr_t(dpy) == 0) {
+        return nullptr;
+    }
+
     uintptr_t index = uintptr_t(dpy)-1U;
     if (index >= NUM_DISPLAYS || !sDisplay[index].isValid()) {
         return nullptr;
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 238cba3..a9e5a43 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -26,6 +26,7 @@
     ],
 
     shared_libs: [
+        "libbase",
         "libbinder",
         "libcrypto",
         "libcutils",
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 99fe0f5..4d9a2a0 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -39,6 +39,7 @@
 
 #include <hardware_legacy/power.h>
 
+#include <android-base/stringprintf.h>
 #include <cutils/properties.h>
 #include <openssl/sha.h>
 #include <utils/Log.h>
@@ -64,6 +65,8 @@
 #define INDENT2 "    "
 #define INDENT3 "      "
 
+using android::base::StringPrintf;
+
 namespace android {
 
 static const char *WAKE_LOCK_ID = "KeyEvents";
@@ -1733,43 +1736,43 @@
     mNeedToReopenDevices = true;
 }
 
-void EventHub::dump(String8& dump) {
-    dump.append("Event Hub State:\n");
+void EventHub::dump(std::string& dump) {
+    dump += "Event Hub State:\n";
 
     { // acquire lock
         AutoMutex _l(mLock);
 
-        dump.appendFormat(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId);
+        dump += StringPrintf(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId);
 
-        dump.append(INDENT "Devices:\n");
+        dump += INDENT "Devices:\n";
 
         for (size_t i = 0; i < mDevices.size(); i++) {
             const Device* device = mDevices.valueAt(i);
             if (mBuiltInKeyboardId == device->id) {
-                dump.appendFormat(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n",
+                dump += StringPrintf(INDENT2 "%d: %s (aka device 0 - built-in keyboard)\n",
                         device->id, device->identifier.name.string());
             } else {
-                dump.appendFormat(INDENT2 "%d: %s\n", device->id,
+                dump += StringPrintf(INDENT2 "%d: %s\n", device->id,
                         device->identifier.name.string());
             }
-            dump.appendFormat(INDENT3 "Classes: 0x%08x\n", device->classes);
-            dump.appendFormat(INDENT3 "Path: %s\n", device->path.string());
-            dump.appendFormat(INDENT3 "Enabled: %s\n", toString(device->enabled));
-            dump.appendFormat(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string());
-            dump.appendFormat(INDENT3 "Location: %s\n", device->identifier.location.string());
-            dump.appendFormat(INDENT3 "ControllerNumber: %d\n", device->controllerNumber);
-            dump.appendFormat(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
-            dump.appendFormat(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
+            dump += StringPrintf(INDENT3 "Classes: 0x%08x\n", device->classes);
+            dump += StringPrintf(INDENT3 "Path: %s\n", device->path.string());
+            dump += StringPrintf(INDENT3 "Enabled: %s\n", toString(device->enabled));
+            dump += StringPrintf(INDENT3 "Descriptor: %s\n", device->identifier.descriptor.string());
+            dump += StringPrintf(INDENT3 "Location: %s\n", device->identifier.location.string());
+            dump += StringPrintf(INDENT3 "ControllerNumber: %d\n", device->controllerNumber);
+            dump += StringPrintf(INDENT3 "UniqueId: %s\n", device->identifier.uniqueId.string());
+            dump += StringPrintf(INDENT3 "Identifier: bus=0x%04x, vendor=0x%04x, "
                     "product=0x%04x, version=0x%04x\n",
                     device->identifier.bus, device->identifier.vendor,
                     device->identifier.product, device->identifier.version);
-            dump.appendFormat(INDENT3 "KeyLayoutFile: %s\n",
+            dump += StringPrintf(INDENT3 "KeyLayoutFile: %s\n",
                     device->keyMap.keyLayoutFile.string());
-            dump.appendFormat(INDENT3 "KeyCharacterMapFile: %s\n",
+            dump += StringPrintf(INDENT3 "KeyCharacterMapFile: %s\n",
                     device->keyMap.keyCharacterMapFile.string());
-            dump.appendFormat(INDENT3 "ConfigurationFile: %s\n",
+            dump += StringPrintf(INDENT3 "ConfigurationFile: %s\n",
                     device->configurationFile.string());
-            dump.appendFormat(INDENT3 "HaveKeyboardLayoutOverlay: %s\n",
+            dump += StringPrintf(INDENT3 "HaveKeyboardLayoutOverlay: %s\n",
                     toString(device->overlayKeyMap != NULL));
         }
     } // release lock
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index 727b73a..66bc294 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -24,7 +24,6 @@
 #include <input/KeyLayoutMap.h>
 #include <input/KeyCharacterMap.h>
 #include <input/VirtualKeyMap.h>
-#include <utils/String8.h>
 #include <utils/Mutex.h>
 #include <utils/Log.h>
 #include <utils/List.h>
@@ -262,7 +261,7 @@
     virtual void wake() = 0;
 
     /* Dump EventHub state to a string. */
-    virtual void dump(String8& dump) = 0;
+    virtual void dump(std::string& dump) = 0;
 
     /* Called by the heatbeat to ensures that the reader has not deadlocked. */
     virtual void monitor() = 0;
@@ -333,7 +332,7 @@
 
     virtual void wake();
 
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void monitor();
 
 protected:
diff --git a/services/inputflinger/InputApplication.h b/services/inputflinger/InputApplication.h
index 1f5504c..724fc2c 100644
--- a/services/inputflinger/InputApplication.h
+++ b/services/inputflinger/InputApplication.h
@@ -18,10 +18,8 @@
 #define _UI_INPUT_APPLICATION_H
 
 #include <input/Input.h>
-
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
-#include <utils/String8.h>
 
 namespace android {
 
@@ -29,7 +27,7 @@
  * Describes the properties of an application that can receive input.
  */
 struct InputApplicationInfo {
-    String8 name;
+    std::string name;
     nsecs_t dispatchingTimeout;
 };
 
@@ -46,8 +44,8 @@
         return mInfo;
     }
 
-    inline String8 getName() const {
-        return mInfo ? mInfo->name : String8("<invalid>");
+    inline std::string getName() const {
+        return mInfo ? mInfo->name : "<invalid>";
     }
 
     inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 8ab30e8..4194dea 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -47,10 +47,12 @@
 
 #include <errno.h>
 #include <limits.h>
+#include <sstream>
 #include <stddef.h>
 #include <time.h>
 #include <unistd.h>
 
+#include <android-base/stringprintf.h>
 #include <log/log.h>
 #include <utils/Trace.h>
 #include <powermanager/PowerManager.h>
@@ -61,6 +63,8 @@
 #define INDENT3 "      "
 #define INDENT4 "        "
 
+using android::base::StringPrintf;
+
 namespace android {
 
 // Default input dispatching timeout if there is no focused application or paused window
@@ -176,9 +180,9 @@
     return displayId == ADISPLAY_ID_DEFAULT || displayId == ADISPLAY_ID_NONE;
 }
 
-static void dumpRegion(String8& dump, const Region& region) {
+static void dumpRegion(std::string& dump, const Region& region) {
     if (region.isEmpty()) {
-        dump.append("<empty>");
+        dump += "<empty>";
         return;
     }
 
@@ -189,9 +193,9 @@
         if (first) {
             first = false;
         } else {
-            dump.append("|");
+            dump += "|";
         }
-        dump.appendFormat("[%d,%d][%d,%d]", cur->left, cur->top, cur->right, cur->bottom);
+        dump += StringPrintf("[%d,%d][%d,%d]", cur->left, cur->top, cur->right, cur->bottom);
         cur++;
     }
 }
@@ -937,7 +941,7 @@
 #if DEBUG_FOCUS
             ALOGD("Dropping event delivery to target with channel '%s' because it "
                     "is no longer registered with the input dispatcher.",
-                    inputTarget.inputChannel->getName().string());
+                    inputTarget.inputChannel->getName().c_str());
 #endif
         }
     }
@@ -963,7 +967,7 @@
         if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY) {
 #if DEBUG_FOCUS
             ALOGD("Waiting for application to become ready for input: %s.  Reason: %s",
-                    getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(),
+                    getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str(),
                     reason);
 #endif
             nsecs_t timeout;
@@ -1070,7 +1074,7 @@
 int32_t InputDispatcher::findFocusedWindowTargetsLocked(nsecs_t currentTime,
         const EventEntry* entry, Vector<InputTarget>& inputTargets, nsecs_t* nextWakeupTime) {
     int32_t injectionResult;
-    String8 reason;
+    std::string reason;
 
     // If there is no currently focused window and no focused application
     // then drop the event.
@@ -1098,9 +1102,9 @@
     // Check whether the window is ready for more input.
     reason = checkWindowReadyForMoreInputLocked(currentTime,
             mFocusedWindowHandle, entry, "focused");
-    if (!reason.isEmpty()) {
+    if (!reason.empty()) {
         injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.string());
+                mFocusedApplicationHandle, mFocusedWindowHandle, nextWakeupTime, reason.c_str());
         goto Unresponsive;
     }
 
@@ -1309,8 +1313,8 @@
                     && newTouchedWindowHandle != NULL) {
 #if DEBUG_FOCUS
                 ALOGD("Touch is slipping out of window %s into window %s.",
-                        oldTouchedWindowHandle->getName().string(),
-                        newTouchedWindowHandle->getName().string());
+                        oldTouchedWindowHandle->getName().c_str(),
+                        newTouchedWindowHandle->getName().c_str());
 #endif
                 // Make a slippery exit from the old window.
                 mTempTouchState.addOrUpdateWindow(oldTouchedWindowHandle,
@@ -1344,7 +1348,7 @@
         if (mLastHoverWindowHandle != NULL) {
 #if DEBUG_HOVER
             ALOGD("Sending hover exit event to window %s.",
-                    mLastHoverWindowHandle->getName().string());
+                    mLastHoverWindowHandle->getName().c_str());
 #endif
             mTempTouchState.addOrUpdateWindow(mLastHoverWindowHandle,
                     InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT, BitSet32(0));
@@ -1354,7 +1358,7 @@
         if (newHoverWindowHandle != NULL) {
 #if DEBUG_HOVER
             ALOGD("Sending hover enter event to window %s.",
-                    newHoverWindowHandle->getName().string());
+                    newHoverWindowHandle->getName().c_str());
 #endif
             mTempTouchState.addOrUpdateWindow(newHoverWindowHandle,
                     InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER, BitSet32(0));
@@ -1412,11 +1416,11 @@
         const TouchedWindow& touchedWindow = mTempTouchState.windows[i];
         if (touchedWindow.targetFlags & InputTarget::FLAG_FOREGROUND) {
             // Check whether the window is ready for more input.
-            String8 reason = checkWindowReadyForMoreInputLocked(currentTime,
+            std::string reason = checkWindowReadyForMoreInputLocked(currentTime,
                     touchedWindow.windowHandle, entry, "touched");
-            if (!reason.isEmpty()) {
+            if (!reason.empty()) {
                 injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                        NULL, touchedWindow.windowHandle, nextWakeupTime, reason.string());
+                        NULL, touchedWindow.windowHandle, nextWakeupTime, reason.c_str());
                 goto Unresponsive;
             }
         }
@@ -1604,7 +1608,7 @@
             ALOGW("Permission denied: injecting event from pid %d uid %d to window %s "
                     "owned by uid %d",
                     injectionState->injectorPid, injectionState->injectorUid,
-                    windowHandle->getName().string(),
+                    windowHandle->getName().c_str(),
                     windowHandle->getInfo()->ownerUid);
         } else {
             ALOGW("Permission denied: injecting event from pid %d uid %d",
@@ -1656,18 +1660,18 @@
     return false;
 }
 
-String8 InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
+std::string InputDispatcher::checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
         const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry,
         const char* targetType) {
     // If the window is paused then keep waiting.
     if (windowHandle->getInfo()->paused) {
-        return String8::format("Waiting because the %s window is paused.", targetType);
+        return StringPrintf("Waiting because the %s window is paused.", targetType);
     }
 
     // If the window's connection is not registered then keep waiting.
     ssize_t connectionIndex = getConnectionIndexLocked(windowHandle->getInputChannel());
     if (connectionIndex < 0) {
-        return String8::format("Waiting because the %s window's input channel is not "
+        return StringPrintf("Waiting because the %s window's input channel is not "
                 "registered with the input dispatcher.  The window may be in the process "
                 "of being removed.", targetType);
     }
@@ -1675,14 +1679,14 @@
     // If the connection is dead then keep waiting.
     sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
     if (connection->status != Connection::STATUS_NORMAL) {
-        return String8::format("Waiting because the %s window's input connection is %s."
+        return StringPrintf("Waiting because the %s window's input connection is %s."
                 "The window may be in the process of being removed.", targetType,
                 connection->getStatusLabel());
     }
 
     // If the connection is backed up then keep waiting.
     if (connection->inputPublisherBlocked) {
-        return String8::format("Waiting because the %s window's input channel is full.  "
+        return StringPrintf("Waiting because the %s window's input channel is full.  "
                 "Outbound queue length: %d.  Wait queue length: %d.",
                 targetType, connection->outboundQueue.count(), connection->waitQueue.count());
     }
@@ -1701,7 +1705,7 @@
         // To obtain this behavior, we must serialize key events with respect to all
         // prior input events.
         if (!connection->outboundQueue.isEmpty() || !connection->waitQueue.isEmpty()) {
-            return String8::format("Waiting to send key event because the %s window has not "
+            return StringPrintf("Waiting to send key event because the %s window has not "
                     "finished processing all of the input events that were previously "
                     "delivered to it.  Outbound queue length: %d.  Wait queue length: %d.",
                     targetType, connection->outboundQueue.count(), connection->waitQueue.count());
@@ -1725,7 +1729,7 @@
         if (!connection->waitQueue.isEmpty()
                 && currentTime >= connection->waitQueue.head->deliveryTime
                         + STREAM_AHEAD_EVENT_TIMEOUT) {
-            return String8::format("Waiting to send non-key event because the %s window has not "
+            return StringPrintf("Waiting to send non-key event because the %s window has not "
                     "finished processing certain input events that were delivered to it over "
                     "%0.1fms ago.  Wait queue length: %d.  Wait queue head age: %0.1fms.",
                     targetType, STREAM_AHEAD_EVENT_TIMEOUT * 0.000001f,
@@ -1733,17 +1737,17 @@
                     (currentTime - connection->waitQueue.head->deliveryTime) * 0.000001f);
         }
     }
-    return String8::empty();
+    return "";
 }
 
-String8 InputDispatcher::getApplicationWindowLabelLocked(
+std::string InputDispatcher::getApplicationWindowLabelLocked(
         const sp<InputApplicationHandle>& applicationHandle,
         const sp<InputWindowHandle>& windowHandle) {
     if (applicationHandle != NULL) {
         if (windowHandle != NULL) {
-            String8 label(applicationHandle->getName());
-            label.append(" - ");
-            label.append(windowHandle->getName());
+            std::string label(applicationHandle->getName());
+            label += " - ";
+            label += windowHandle->getName();
             return label;
         } else {
             return applicationHandle->getName();
@@ -1751,7 +1755,7 @@
     } else if (windowHandle != NULL) {
         return windowHandle->getName();
     } else {
-        return String8("<unknown application or window>");
+        return "<unknown application or window>";
     }
 }
 
@@ -1760,7 +1764,7 @@
         const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
         if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) {
 #if DEBUG_DISPATCH_CYCLE
-            ALOGD("Not poking user activity: disabled by window '%s'.", info->name.string());
+            ALOGD("Not poking user activity: disabled by window '%s'.", info->name.c_str());
 #endif
             return;
         }
@@ -2882,7 +2886,7 @@
             if (mFocusedWindowHandle != NULL) {
 #if DEBUG_FOCUS
                 ALOGD("Focus left window: %s",
-                        mFocusedWindowHandle->getName().string());
+                        mFocusedWindowHandle->getName().c_str());
 #endif
                 sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel();
                 if (focusedInputChannel != NULL) {
@@ -2895,7 +2899,7 @@
             if (newFocusedWindowHandle != NULL) {
 #if DEBUG_FOCUS
                 ALOGD("Focus entered window: %s",
-                        newFocusedWindowHandle->getName().string());
+                        newFocusedWindowHandle->getName().c_str());
 #endif
             }
             mFocusedWindowHandle = newFocusedWindowHandle;
@@ -2908,7 +2912,7 @@
                 if (!hasWindowHandleLocked(touchedWindow.windowHandle)) {
 #if DEBUG_FOCUS
                     ALOGD("Touched window was removed: %s",
-                            touchedWindow.windowHandle->getName().string());
+                            touchedWindow.windowHandle->getName().c_str());
 #endif
                     sp<InputChannel> touchedInputChannel =
                             touchedWindow.windowHandle->getInputChannel();
@@ -2933,7 +2937,7 @@
             const sp<InputWindowHandle>& oldWindowHandle = oldWindowHandles.itemAt(i);
             if (!hasWindowHandleLocked(oldWindowHandle)) {
 #if DEBUG_FOCUS
-                ALOGD("Window went away: %s", oldWindowHandle->getName().string());
+                ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
 #endif
                 oldWindowHandle->releaseInfo();
             }
@@ -3035,7 +3039,7 @@
         const sp<InputChannel>& toChannel) {
 #if DEBUG_FOCUS
     ALOGD("transferTouchFocus: fromChannel=%s, toChannel=%s",
-            fromChannel->getName().string(), toChannel->getName().string());
+            fromChannel->getName().c_str(), toChannel->getName().c_str());
 #endif
     { // acquire lock
         AutoMutex _l(mLock);
@@ -3132,72 +3136,68 @@
 }
 
 void InputDispatcher::logDispatchStateLocked() {
-    String8 dump;
+    std::string dump;
     dumpDispatchStateLocked(dump);
 
-    char* text = dump.lockBuffer(dump.size());
-    char* start = text;
-    while (*start != '\0') {
-        char* end = strchr(start, '\n');
-        if (*end == '\n') {
-            *(end++) = '\0';
-        }
-        ALOGD("%s", start);
-        start = end;
+    std::istringstream stream(dump);
+    std::string line;
+
+    while (std::getline(stream, line, '\n')) {
+        ALOGD("%s", line.c_str());
     }
 }
 
-void InputDispatcher::dumpDispatchStateLocked(String8& dump) {
-    dump.appendFormat(INDENT "DispatchEnabled: %d\n", mDispatchEnabled);
-    dump.appendFormat(INDENT "DispatchFrozen: %d\n", mDispatchFrozen);
+void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
+    dump += StringPrintf(INDENT "DispatchEnabled: %d\n", mDispatchEnabled);
+    dump += StringPrintf(INDENT "DispatchFrozen: %d\n", mDispatchFrozen);
 
     if (mFocusedApplicationHandle != NULL) {
-        dump.appendFormat(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
-                mFocusedApplicationHandle->getName().string(),
+        dump += StringPrintf(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
+                mFocusedApplicationHandle->getName().c_str(),
                 mFocusedApplicationHandle->getDispatchingTimeout(
                         DEFAULT_INPUT_DISPATCHING_TIMEOUT) / 1000000.0);
     } else {
-        dump.append(INDENT "FocusedApplication: <null>\n");
+        dump += StringPrintf(INDENT "FocusedApplication: <null>\n");
     }
-    dump.appendFormat(INDENT "FocusedWindow: name='%s'\n",
-            mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().string() : "<null>");
+    dump += StringPrintf(INDENT "FocusedWindow: name='%s'\n",
+            mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().c_str() : "<null>");
 
     if (!mTouchStatesByDisplay.isEmpty()) {
-        dump.appendFormat(INDENT "TouchStatesByDisplay:\n");
+        dump += StringPrintf(INDENT "TouchStatesByDisplay:\n");
         for (size_t i = 0; i < mTouchStatesByDisplay.size(); i++) {
             const TouchState& state = mTouchStatesByDisplay.valueAt(i);
-            dump.appendFormat(INDENT2 "%d: down=%s, split=%s, deviceId=%d, source=0x%08x\n",
+            dump += StringPrintf(INDENT2 "%d: down=%s, split=%s, deviceId=%d, source=0x%08x\n",
                     state.displayId, toString(state.down), toString(state.split),
                     state.deviceId, state.source);
             if (!state.windows.isEmpty()) {
-                dump.append(INDENT3 "Windows:\n");
+                dump += INDENT3 "Windows:\n";
                 for (size_t i = 0; i < state.windows.size(); i++) {
                     const TouchedWindow& touchedWindow = state.windows[i];
-                    dump.appendFormat(INDENT4 "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n",
-                            i, touchedWindow.windowHandle->getName().string(),
+                    dump += StringPrintf(INDENT4 "%zu: name='%s', pointerIds=0x%0x, targetFlags=0x%x\n",
+                            i, touchedWindow.windowHandle->getName().c_str(),
                             touchedWindow.pointerIds.value,
                             touchedWindow.targetFlags);
                 }
             } else {
-                dump.append(INDENT3 "Windows: <none>\n");
+                dump += INDENT3 "Windows: <none>\n";
             }
         }
     } else {
-        dump.append(INDENT "TouchStates: <no displays touched>\n");
+        dump += INDENT "TouchStates: <no displays touched>\n";
     }
 
     if (!mWindowHandles.isEmpty()) {
-        dump.append(INDENT "Windows:\n");
+        dump += INDENT "Windows:\n";
         for (size_t i = 0; i < mWindowHandles.size(); i++) {
             const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
             const InputWindowInfo* windowInfo = windowHandle->getInfo();
 
-            dump.appendFormat(INDENT2 "%zu: name='%s', displayId=%d, "
+            dump += StringPrintf(INDENT2 "%zu: name='%s', displayId=%d, "
                     "paused=%s, hasFocus=%s, hasWallpaper=%s, "
                     "visible=%s, canReceiveKeys=%s, flags=0x%08x, type=0x%08x, layer=%d, "
                     "frame=[%d,%d][%d,%d], scale=%f, "
                     "touchableRegion=",
-                    i, windowInfo->name.string(), windowInfo->displayId,
+                    i, windowInfo->name.c_str(), windowInfo->displayId,
                     toString(windowInfo->paused),
                     toString(windowInfo->hasFocus),
                     toString(windowInfo->hasWallpaper),
@@ -3209,140 +3209,140 @@
                     windowInfo->frameRight, windowInfo->frameBottom,
                     windowInfo->scaleFactor);
             dumpRegion(dump, windowInfo->touchableRegion);
-            dump.appendFormat(", inputFeatures=0x%08x", windowInfo->inputFeatures);
-            dump.appendFormat(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
+            dump += StringPrintf(", inputFeatures=0x%08x", windowInfo->inputFeatures);
+            dump += StringPrintf(", ownerPid=%d, ownerUid=%d, dispatchingTimeout=%0.3fms\n",
                     windowInfo->ownerPid, windowInfo->ownerUid,
                     windowInfo->dispatchingTimeout / 1000000.0);
         }
     } else {
-        dump.append(INDENT "Windows: <none>\n");
+        dump += INDENT "Windows: <none>\n";
     }
 
     if (!mMonitoringChannels.isEmpty()) {
-        dump.append(INDENT "MonitoringChannels:\n");
+        dump += INDENT "MonitoringChannels:\n";
         for (size_t i = 0; i < mMonitoringChannels.size(); i++) {
             const sp<InputChannel>& channel = mMonitoringChannels[i];
-            dump.appendFormat(INDENT2 "%zu: '%s'\n", i, channel->getName().string());
+            dump += StringPrintf(INDENT2 "%zu: '%s'\n", i, channel->getName().c_str());
         }
     } else {
-        dump.append(INDENT "MonitoringChannels: <none>\n");
+        dump += INDENT "MonitoringChannels: <none>\n";
     }
 
     nsecs_t currentTime = now();
 
     // Dump recently dispatched or dropped events from oldest to newest.
     if (!mRecentQueue.isEmpty()) {
-        dump.appendFormat(INDENT "RecentQueue: length=%u\n", mRecentQueue.count());
+        dump += StringPrintf(INDENT "RecentQueue: length=%u\n", mRecentQueue.count());
         for (EventEntry* entry = mRecentQueue.head; entry; entry = entry->next) {
-            dump.append(INDENT2);
+            dump += INDENT2;
             entry->appendDescription(dump);
-            dump.appendFormat(", age=%0.1fms\n",
+            dump += StringPrintf(", age=%0.1fms\n",
                     (currentTime - entry->eventTime) * 0.000001f);
         }
     } else {
-        dump.append(INDENT "RecentQueue: <empty>\n");
+        dump += INDENT "RecentQueue: <empty>\n";
     }
 
     // Dump event currently being dispatched.
     if (mPendingEvent) {
-        dump.append(INDENT "PendingEvent:\n");
-        dump.append(INDENT2);
+        dump += INDENT "PendingEvent:\n";
+        dump += INDENT2;
         mPendingEvent->appendDescription(dump);
-        dump.appendFormat(", age=%0.1fms\n",
+        dump += StringPrintf(", age=%0.1fms\n",
                 (currentTime - mPendingEvent->eventTime) * 0.000001f);
     } else {
-        dump.append(INDENT "PendingEvent: <none>\n");
+        dump += INDENT "PendingEvent: <none>\n";
     }
 
     // Dump inbound events from oldest to newest.
     if (!mInboundQueue.isEmpty()) {
-        dump.appendFormat(INDENT "InboundQueue: length=%u\n", mInboundQueue.count());
+        dump += StringPrintf(INDENT "InboundQueue: length=%u\n", mInboundQueue.count());
         for (EventEntry* entry = mInboundQueue.head; entry; entry = entry->next) {
-            dump.append(INDENT2);
+            dump += INDENT2;
             entry->appendDescription(dump);
-            dump.appendFormat(", age=%0.1fms\n",
+            dump += StringPrintf(", age=%0.1fms\n",
                     (currentTime - entry->eventTime) * 0.000001f);
         }
     } else {
-        dump.append(INDENT "InboundQueue: <empty>\n");
+        dump += INDENT "InboundQueue: <empty>\n";
     }
 
     if (!mReplacedKeys.isEmpty()) {
-        dump.append(INDENT "ReplacedKeys:\n");
+        dump += INDENT "ReplacedKeys:\n";
         for (size_t i = 0; i < mReplacedKeys.size(); i++) {
             const KeyReplacement& replacement = mReplacedKeys.keyAt(i);
             int32_t newKeyCode = mReplacedKeys.valueAt(i);
-            dump.appendFormat(INDENT2 "%zu: originalKeyCode=%d, deviceId=%d, newKeyCode=%d\n",
+            dump += StringPrintf(INDENT2 "%zu: originalKeyCode=%d, deviceId=%d, newKeyCode=%d\n",
                     i, replacement.keyCode, replacement.deviceId, newKeyCode);
         }
     } else {
-        dump.append(INDENT "ReplacedKeys: <empty>\n");
+        dump += INDENT "ReplacedKeys: <empty>\n";
     }
 
     if (!mConnectionsByFd.isEmpty()) {
-        dump.append(INDENT "Connections:\n");
+        dump += INDENT "Connections:\n";
         for (size_t i = 0; i < mConnectionsByFd.size(); i++) {
             const sp<Connection>& connection = mConnectionsByFd.valueAt(i);
-            dump.appendFormat(INDENT2 "%zu: channelName='%s', windowName='%s', "
+            dump += StringPrintf(INDENT2 "%zu: channelName='%s', windowName='%s', "
                     "status=%s, monitor=%s, inputPublisherBlocked=%s\n",
                     i, connection->getInputChannelName(), connection->getWindowName(),
                     connection->getStatusLabel(), toString(connection->monitor),
                     toString(connection->inputPublisherBlocked));
 
             if (!connection->outboundQueue.isEmpty()) {
-                dump.appendFormat(INDENT3 "OutboundQueue: length=%u\n",
+                dump += StringPrintf(INDENT3 "OutboundQueue: length=%u\n",
                         connection->outboundQueue.count());
                 for (DispatchEntry* entry = connection->outboundQueue.head; entry;
                         entry = entry->next) {
                     dump.append(INDENT4);
                     entry->eventEntry->appendDescription(dump);
-                    dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n",
+                    dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, age=%0.1fms\n",
                             entry->targetFlags, entry->resolvedAction,
                             (currentTime - entry->eventEntry->eventTime) * 0.000001f);
                 }
             } else {
-                dump.append(INDENT3 "OutboundQueue: <empty>\n");
+                dump += INDENT3 "OutboundQueue: <empty>\n";
             }
 
             if (!connection->waitQueue.isEmpty()) {
-                dump.appendFormat(INDENT3 "WaitQueue: length=%u\n",
+                dump += StringPrintf(INDENT3 "WaitQueue: length=%u\n",
                         connection->waitQueue.count());
                 for (DispatchEntry* entry = connection->waitQueue.head; entry;
                         entry = entry->next) {
-                    dump.append(INDENT4);
+                    dump += INDENT4;
                     entry->eventEntry->appendDescription(dump);
-                    dump.appendFormat(", targetFlags=0x%08x, resolvedAction=%d, "
+                    dump += StringPrintf(", targetFlags=0x%08x, resolvedAction=%d, "
                             "age=%0.1fms, wait=%0.1fms\n",
                             entry->targetFlags, entry->resolvedAction,
                             (currentTime - entry->eventEntry->eventTime) * 0.000001f,
                             (currentTime - entry->deliveryTime) * 0.000001f);
                 }
             } else {
-                dump.append(INDENT3 "WaitQueue: <empty>\n");
+                dump += INDENT3 "WaitQueue: <empty>\n";
             }
         }
     } else {
-        dump.append(INDENT "Connections: <none>\n");
+        dump += INDENT "Connections: <none>\n";
     }
 
     if (isAppSwitchPendingLocked()) {
-        dump.appendFormat(INDENT "AppSwitch: pending, due in %0.1fms\n",
+        dump += StringPrintf(INDENT "AppSwitch: pending, due in %0.1fms\n",
                 (mAppSwitchDueTime - now()) / 1000000.0);
     } else {
-        dump.append(INDENT "AppSwitch: not pending\n");
+        dump += INDENT "AppSwitch: not pending\n";
     }
 
-    dump.append(INDENT "Configuration:\n");
-    dump.appendFormat(INDENT2 "KeyRepeatDelay: %0.1fms\n",
+    dump += INDENT "Configuration:\n";
+    dump += StringPrintf(INDENT2 "KeyRepeatDelay: %0.1fms\n",
             mConfig.keyRepeatDelay * 0.000001f);
-    dump.appendFormat(INDENT2 "KeyRepeatTimeout: %0.1fms\n",
+    dump += StringPrintf(INDENT2 "KeyRepeatTimeout: %0.1fms\n",
             mConfig.keyRepeatTimeout * 0.000001f);
 }
 
 status_t InputDispatcher::registerInputChannel(const sp<InputChannel>& inputChannel,
         const sp<InputWindowHandle>& inputWindowHandle, bool monitor) {
 #if DEBUG_REGISTRATION
-    ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().string(),
+    ALOGD("channel '%s' ~ registerInputChannel - monitor=%s", inputChannel->getName().c_str(),
             toString(monitor));
 #endif
 
@@ -3351,7 +3351,7 @@
 
         if (getConnectionIndexLocked(inputChannel) >= 0) {
             ALOGW("Attempted to register already registered input channel '%s'",
-                    inputChannel->getName().string());
+                    inputChannel->getName().c_str());
             return BAD_VALUE;
         }
 
@@ -3374,7 +3374,7 @@
 
 status_t InputDispatcher::unregisterInputChannel(const sp<InputChannel>& inputChannel) {
 #if DEBUG_REGISTRATION
-    ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().string());
+    ALOGD("channel '%s' ~ unregisterInputChannel", inputChannel->getName().c_str());
 #endif
 
     { // acquire lock
@@ -3397,7 +3397,7 @@
     ssize_t connectionIndex = getConnectionIndexLocked(inputChannel);
     if (connectionIndex < 0) {
         ALOGW("Attempted to unregister already unregistered input channel '%s'",
-                inputChannel->getName().string());
+                inputChannel->getName().c_str());
         return BAD_VALUE;
     }
 
@@ -3466,7 +3466,7 @@
     float waitDuration = (currentTime - waitStartTime) * 0.000001f;
     ALOGI("Application is not responding: %s.  "
             "It has been %0.1fms since event, %0.1fms since wait started.  Reason: %s",
-            getApplicationWindowLabelLocked(applicationHandle, windowHandle).string(),
+            getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str(),
             dispatchLatency, waitDuration, reason);
 
     // Capture a record of the InputDispatcher state at the time of the ANR.
@@ -3476,13 +3476,13 @@
     char timestr[64];
     strftime(timestr, sizeof(timestr), "%F %T", &tm);
     mLastANRState.clear();
-    mLastANRState.append(INDENT "ANR:\n");
-    mLastANRState.appendFormat(INDENT2 "Time: %s\n", timestr);
-    mLastANRState.appendFormat(INDENT2 "Window: %s\n",
-            getApplicationWindowLabelLocked(applicationHandle, windowHandle).string());
-    mLastANRState.appendFormat(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency);
-    mLastANRState.appendFormat(INDENT2 "WaitDuration: %0.1fms\n", waitDuration);
-    mLastANRState.appendFormat(INDENT2 "Reason: %s\n", reason);
+    mLastANRState += INDENT "ANR:\n";
+    mLastANRState += StringPrintf(INDENT2 "Time: %s\n", timestr);
+    mLastANRState += StringPrintf(INDENT2 "Window: %s\n",
+            getApplicationWindowLabelLocked(applicationHandle, windowHandle).c_str());
+    mLastANRState += StringPrintf(INDENT2 "DispatchLatency: %0.1fms\n", dispatchLatency);
+    mLastANRState += StringPrintf(INDENT2 "WaitDuration: %0.1fms\n", waitDuration);
+    mLastANRState += StringPrintf(INDENT2 "Reason: %s\n", reason);
     dumpDispatchStateLocked(mLastANRState);
 
     CommandEntry* commandEntry = postCommandLocked(
@@ -3566,11 +3566,11 @@
     if (dispatchEntry) {
         nsecs_t eventDuration = finishTime - dispatchEntry->deliveryTime;
         if (eventDuration > SLOW_EVENT_PROCESSING_WARNING_TIMEOUT) {
-            String8 msg;
-            msg.appendFormat("Window '%s' spent %0.1fms processing the last input event: ",
+            std::string msg =
+                    StringPrintf("Window '%s' spent %0.1fms processing the last input event: ",
                     connection->getWindowName(), eventDuration * 0.000001f);
             dispatchEntry->eventEntry->appendDescription(msg);
-            ALOGI("%s", msg.string());
+            ALOGI("%s", msg.c_str());
         }
 
         bool restartEvent;
@@ -3737,15 +3737,15 @@
 
 #if DEBUG_OUTBOUND_EVENT_DETAILS
             {
-                String8 msg;
+                std::string msg;
                 const KeyedVector<int32_t, int32_t>& fallbackKeys =
                         connection->inputState.getFallbackKeys();
                 for (size_t i = 0; i < fallbackKeys.size(); i++) {
-                    msg.appendFormat(", %d->%d", fallbackKeys.keyAt(i),
+                    msg += StringPrintf(", %d->%d", fallbackKeys.keyAt(i),
                             fallbackKeys.valueAt(i));
                 }
                 ALOGD("Unhandled key event: %zu currently tracked fallback keys%s.",
-                        fallbackKeys.size(), msg.string());
+                        fallbackKeys.size(), msg.c_str());
             }
 #endif
 
@@ -3824,15 +3824,15 @@
     }
 }
 
-void InputDispatcher::dump(String8& dump) {
+void InputDispatcher::dump(std::string& dump) {
     AutoMutex _l(mLock);
 
-    dump.append("Input Dispatcher State:\n");
+    dump += "Input Dispatcher State:\n";
     dumpDispatchStateLocked(dump);
 
-    if (!mLastANRState.isEmpty()) {
-        dump.append("\nInput Dispatcher State at time of last ANR:\n");
-        dump.append(mLastANRState);
+    if (!mLastANRState.empty()) {
+        dump += "\nInput Dispatcher State at time of last ANR:\n";
+        dump += mLastANRState;
     }
 }
 
@@ -3904,9 +3904,8 @@
 InputDispatcher::ConfigurationChangedEntry::~ConfigurationChangedEntry() {
 }
 
-void InputDispatcher::ConfigurationChangedEntry::appendDescription(String8& msg) const {
-    msg.append("ConfigurationChangedEvent(), policyFlags=0x%08x",
-            policyFlags);
+void InputDispatcher::ConfigurationChangedEntry::appendDescription(std::string& msg) const {
+    msg += StringPrintf("ConfigurationChangedEvent(), policyFlags=0x%08x", policyFlags);
 }
 
 
@@ -3920,8 +3919,8 @@
 InputDispatcher::DeviceResetEntry::~DeviceResetEntry() {
 }
 
-void InputDispatcher::DeviceResetEntry::appendDescription(String8& msg) const {
-    msg.appendFormat("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x",
+void InputDispatcher::DeviceResetEntry::appendDescription(std::string& msg) const {
+    msg += StringPrintf("DeviceResetEvent(deviceId=%d), policyFlags=0x%08x",
             deviceId, policyFlags);
 }
 
@@ -3943,8 +3942,8 @@
 InputDispatcher::KeyEntry::~KeyEntry() {
 }
 
-void InputDispatcher::KeyEntry::appendDescription(String8& msg) const {
-    msg.appendFormat("KeyEvent(deviceId=%d, source=0x%08x, action=%d, "
+void InputDispatcher::KeyEntry::appendDescription(std::string& msg) const {
+    msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, action=%d, "
             "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, "
             "repeatCount=%d), policyFlags=0x%08x",
             deviceId, source, action, flags, keyCode, scanCode, metaState,
@@ -3988,20 +3987,20 @@
 InputDispatcher::MotionEntry::~MotionEntry() {
 }
 
-void InputDispatcher::MotionEntry::appendDescription(String8& msg) const {
-    msg.appendFormat("MotionEvent(deviceId=%d, source=0x%08x, action=%d, actionButton=0x%08x, "
+void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const {
+    msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, action=%d, actionButton=0x%08x, "
             "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, "
             "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[",
             deviceId, source, action, actionButton, flags, metaState, buttonState, edgeFlags,
             xPrecision, yPrecision, displayId);
     for (uint32_t i = 0; i < pointerCount; i++) {
         if (i) {
-            msg.append(", ");
+            msg += ", ";
         }
-        msg.appendFormat("%d: (%.1f, %.1f)", pointerProperties[i].id,
+        msg += StringPrintf("%d: (%.1f, %.1f)", pointerProperties[i].id,
                 pointerCoords[i].getX(), pointerCoords[i].getY());
     }
-    msg.appendFormat("]), policyFlags=0x%08x", policyFlags);
+    msg += StringPrintf("]), policyFlags=0x%08x", policyFlags);
 }
 
 
@@ -4400,7 +4399,7 @@
 
 const char* InputDispatcher::Connection::getWindowName() const {
     if (inputWindowHandle != NULL) {
-        return inputWindowHandle->getName().string();
+        return inputWindowHandle->getName().c_str();
     }
     if (monitor) {
         return "monitor";
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 90c69ce..92b3a9c 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -24,7 +24,6 @@
 #include <utils/threads.h>
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
-#include <utils/String8.h>
 #include <utils/Looper.h>
 #include <utils/BitSet.h>
 #include <cutils/atomic.h>
@@ -209,7 +208,7 @@
      * Returns a new timeout to continue waiting, or 0 to abort dispatch. */
     virtual nsecs_t notifyANR(const sp<InputApplicationHandle>& inputApplicationHandle,
             const sp<InputWindowHandle>& inputWindowHandle,
-            const String8& reason) = 0;
+            const std::string& reason) = 0;
 
     /* Notifies the system that an input channel is unrecoverably broken. */
     virtual void notifyInputChannelBroken(const sp<InputWindowHandle>& inputWindowHandle) = 0;
@@ -281,7 +280,7 @@
     /* Dumps the state of the input dispatcher.
      *
      * This method may be called on any thread (usually by the input manager). */
-    virtual void dump(String8& dump) = 0;
+    virtual void dump(std::string& dump) = 0;
 
     /* Called by the heatbeat to ensures that the dispatcher has not deadlocked. */
     virtual void monitor() = 0;
@@ -373,7 +372,7 @@
 public:
     explicit InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy);
 
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void monitor();
 
     virtual void dispatchOnce();
@@ -446,7 +445,7 @@
 
         void release();
 
-        virtual void appendDescription(String8& msg) const = 0;
+        virtual void appendDescription(std::string& msg) const = 0;
 
     protected:
         EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags);
@@ -456,7 +455,7 @@
 
     struct ConfigurationChangedEntry : EventEntry {
         explicit ConfigurationChangedEntry(nsecs_t eventTime);
-        virtual void appendDescription(String8& msg) const;
+        virtual void appendDescription(std::string& msg) const;
 
     protected:
         virtual ~ConfigurationChangedEntry();
@@ -466,7 +465,7 @@
         int32_t deviceId;
 
         DeviceResetEntry(nsecs_t eventTime, int32_t deviceId);
-        virtual void appendDescription(String8& msg) const;
+        virtual void appendDescription(std::string& msg) const;
 
     protected:
         virtual ~DeviceResetEntry();
@@ -498,7 +497,7 @@
                 int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action,
                 int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
                 int32_t repeatCount, nsecs_t downTime);
-        virtual void appendDescription(String8& msg) const;
+        virtual void appendDescription(std::string& msg) const;
         void recycle();
 
     protected:
@@ -531,7 +530,7 @@
                 int32_t displayId, uint32_t pointerCount,
                 const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
                 float xOffset, float yOffset);
-        virtual void appendDescription(String8& msg) const;
+        virtual void appendDescription(std::string& msg) const;
 
     protected:
         virtual ~MotionEntry();
@@ -602,7 +601,7 @@
         KeyEntry* keyEntry;
         sp<InputApplicationHandle> inputApplicationHandle;
         sp<InputWindowHandle> inputWindowHandle;
-        String8 reason;
+        std::string reason;
         int32_t userActivityEventType;
         uint32_t seq;
         bool handled;
@@ -832,7 +831,7 @@
         explicit Connection(const sp<InputChannel>& inputChannel,
                 const sp<InputWindowHandle>& inputWindowHandle, bool monitor);
 
-        inline const char* getInputChannelName() const { return inputChannel->getName().string(); }
+        inline const char* getInputChannelName() const { return inputChannel->getName().c_str(); }
 
         const char* getWindowName() const;
         const char* getStatusLabel() const;
@@ -994,7 +993,7 @@
     sp<InputApplicationHandle> mFocusedApplicationHandle;
 
     // Dispatcher state at time of last ANR.
-    String8 mLastANRState;
+    std::string mLastANRState;
 
     // Dispatch inbound events.
     bool dispatchConfigurationChangedLocked(
@@ -1055,10 +1054,10 @@
     bool isWindowObscuredAtPointLocked(const sp<InputWindowHandle>& windowHandle,
             int32_t x, int32_t y) const;
     bool isWindowObscuredLocked(const sp<InputWindowHandle>& windowHandle) const;
-    String8 getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
+    std::string getApplicationWindowLabelLocked(const sp<InputApplicationHandle>& applicationHandle,
             const sp<InputWindowHandle>& windowHandle);
 
-    String8 checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
+    std::string checkWindowReadyForMoreInputLocked(nsecs_t currentTime,
             const sp<InputWindowHandle>& windowHandle, const EventEntry* eventEntry,
             const char* targetType);
 
@@ -1096,7 +1095,7 @@
     void resetAndDropEverythingLocked(const char* reason);
 
     // Dump state.
-    void dumpDispatchStateLocked(String8& dump);
+    void dumpDispatchStateLocked(std::string& dump);
     void logDispatchStateLocked();
 
     // Registration.
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 591f8d7..76ea889 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -54,6 +54,7 @@
 
 #include <log/log.h>
 
+#include <android-base/stringprintf.h>
 #include <input/Keyboard.h>
 #include <input/VirtualKeyMap.h>
 
@@ -63,6 +64,8 @@
 #define INDENT4 "        "
 #define INDENT5 "          "
 
+using android::base::StringPrintf;
+
 namespace android {
 
 // --- Constants ---
@@ -290,19 +293,19 @@
     mVirtualDisplays = viewports;
 }
 
-void InputReaderConfiguration::dump(String8& dump) const {
-    dump.append(INDENT4 "ViewportInternal:\n");
+void InputReaderConfiguration::dump(std::string& dump) const {
+    dump += INDENT4 "ViewportInternal:\n";
     dumpViewport(dump, mInternalDisplay);
-    dump.append(INDENT4 "ViewportExternal:\n");
+    dump += INDENT4 "ViewportExternal:\n";
     dumpViewport(dump, mExternalDisplay);
-    dump.append(INDENT4 "ViewportVirtual:\n");
+    dump += INDENT4 "ViewportVirtual:\n";
     for (const DisplayViewport& viewport : mVirtualDisplays) {
         dumpViewport(dump, viewport);
     }
 }
 
-void InputReaderConfiguration::dumpViewport(String8& dump, const DisplayViewport& viewport) const {
-    dump.appendFormat(INDENT5 "Viewport: displayId=%d, orientation=%d, uniqueId='%s', "
+void InputReaderConfiguration::dumpViewport(std::string& dump, const DisplayViewport& viewport) const {
+    dump += StringPrintf(INDENT5 "Viewport: displayId=%d, orientation=%d, uniqueId='%s', "
             "logicalFrame=[%d, %d, %d, %d], "
             "physicalFrame=[%d, %d, %d, %d], "
             "deviceSize=[%d, %d]\n",
@@ -873,71 +876,71 @@
     return false;
 }
 
-void InputReader::dump(String8& dump) {
+void InputReader::dump(std::string& dump) {
     AutoMutex _l(mLock);
 
     mEventHub->dump(dump);
-    dump.append("\n");
+    dump += "\n";
 
-    dump.append("Input Reader State:\n");
+    dump += "Input Reader State:\n";
 
     for (size_t i = 0; i < mDevices.size(); i++) {
         mDevices.valueAt(i)->dump(dump);
     }
 
-    dump.append(INDENT "Configuration:\n");
-    dump.append(INDENT2 "ExcludedDeviceNames: [");
+    dump += INDENT "Configuration:\n";
+    dump += INDENT2 "ExcludedDeviceNames: [";
     for (size_t i = 0; i < mConfig.excludedDeviceNames.size(); i++) {
         if (i != 0) {
-            dump.append(", ");
+            dump += ", ";
         }
-        dump.append(mConfig.excludedDeviceNames.itemAt(i).string());
+        dump += mConfig.excludedDeviceNames.itemAt(i).string();
     }
-    dump.append("]\n");
-    dump.appendFormat(INDENT2 "VirtualKeyQuietTime: %0.1fms\n",
+    dump += "]\n";
+    dump += StringPrintf(INDENT2 "VirtualKeyQuietTime: %0.1fms\n",
             mConfig.virtualKeyQuietTime * 0.000001f);
 
-    dump.appendFormat(INDENT2 "PointerVelocityControlParameters: "
+    dump += StringPrintf(INDENT2 "PointerVelocityControlParameters: "
             "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n",
             mConfig.pointerVelocityControlParameters.scale,
             mConfig.pointerVelocityControlParameters.lowThreshold,
             mConfig.pointerVelocityControlParameters.highThreshold,
             mConfig.pointerVelocityControlParameters.acceleration);
 
-    dump.appendFormat(INDENT2 "WheelVelocityControlParameters: "
+    dump += StringPrintf(INDENT2 "WheelVelocityControlParameters: "
             "scale=%0.3f, lowThreshold=%0.3f, highThreshold=%0.3f, acceleration=%0.3f\n",
             mConfig.wheelVelocityControlParameters.scale,
             mConfig.wheelVelocityControlParameters.lowThreshold,
             mConfig.wheelVelocityControlParameters.highThreshold,
             mConfig.wheelVelocityControlParameters.acceleration);
 
-    dump.appendFormat(INDENT2 "PointerGesture:\n");
-    dump.appendFormat(INDENT3 "Enabled: %s\n",
+    dump += StringPrintf(INDENT2 "PointerGesture:\n");
+    dump += StringPrintf(INDENT3 "Enabled: %s\n",
             toString(mConfig.pointerGesturesEnabled));
-    dump.appendFormat(INDENT3 "QuietInterval: %0.1fms\n",
+    dump += StringPrintf(INDENT3 "QuietInterval: %0.1fms\n",
             mConfig.pointerGestureQuietInterval * 0.000001f);
-    dump.appendFormat(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n",
+    dump += StringPrintf(INDENT3 "DragMinSwitchSpeed: %0.1fpx/s\n",
             mConfig.pointerGestureDragMinSwitchSpeed);
-    dump.appendFormat(INDENT3 "TapInterval: %0.1fms\n",
+    dump += StringPrintf(INDENT3 "TapInterval: %0.1fms\n",
             mConfig.pointerGestureTapInterval * 0.000001f);
-    dump.appendFormat(INDENT3 "TapDragInterval: %0.1fms\n",
+    dump += StringPrintf(INDENT3 "TapDragInterval: %0.1fms\n",
             mConfig.pointerGestureTapDragInterval * 0.000001f);
-    dump.appendFormat(INDENT3 "TapSlop: %0.1fpx\n",
+    dump += StringPrintf(INDENT3 "TapSlop: %0.1fpx\n",
             mConfig.pointerGestureTapSlop);
-    dump.appendFormat(INDENT3 "MultitouchSettleInterval: %0.1fms\n",
+    dump += StringPrintf(INDENT3 "MultitouchSettleInterval: %0.1fms\n",
             mConfig.pointerGestureMultitouchSettleInterval * 0.000001f);
-    dump.appendFormat(INDENT3 "MultitouchMinDistance: %0.1fpx\n",
+    dump += StringPrintf(INDENT3 "MultitouchMinDistance: %0.1fpx\n",
             mConfig.pointerGestureMultitouchMinDistance);
-    dump.appendFormat(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n",
+    dump += StringPrintf(INDENT3 "SwipeTransitionAngleCosine: %0.1f\n",
             mConfig.pointerGestureSwipeTransitionAngleCosine);
-    dump.appendFormat(INDENT3 "SwipeMaxWidthRatio: %0.1f\n",
+    dump += StringPrintf(INDENT3 "SwipeMaxWidthRatio: %0.1f\n",
             mConfig.pointerGestureSwipeMaxWidthRatio);
-    dump.appendFormat(INDENT3 "MovementSpeedRatio: %0.1f\n",
+    dump += StringPrintf(INDENT3 "MovementSpeedRatio: %0.1f\n",
             mConfig.pointerGestureMovementSpeedRatio);
-    dump.appendFormat(INDENT3 "ZoomSpeedRatio: %0.1f\n",
+    dump += StringPrintf(INDENT3 "ZoomSpeedRatio: %0.1f\n",
             mConfig.pointerGestureZoomSpeedRatio);
 
-    dump.append(INDENT3 "Viewports:\n");
+    dump += INDENT3 "Viewports:\n";
     mConfig.dump(dump);
 }
 
@@ -1069,21 +1072,21 @@
     bumpGeneration();
 }
 
-void InputDevice::dump(String8& dump) {
+void InputDevice::dump(std::string& dump) {
     InputDeviceInfo deviceInfo;
     getDeviceInfo(& deviceInfo);
 
-    dump.appendFormat(INDENT "Device %d: %s\n", deviceInfo.getId(),
+    dump += StringPrintf(INDENT "Device %d: %s\n", deviceInfo.getId(),
             deviceInfo.getDisplayName().string());
-    dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration);
-    dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
-    dump.appendFormat(INDENT2 "HasMic:     %s\n", toString(mHasMic));
-    dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
-    dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
+    dump += StringPrintf(INDENT2 "Generation: %d\n", mGeneration);
+    dump += StringPrintf(INDENT2 "IsExternal: %s\n", toString(mIsExternal));
+    dump += StringPrintf(INDENT2 "HasMic:     %s\n", toString(mHasMic));
+    dump += StringPrintf(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources());
+    dump += StringPrintf(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType());
 
     const Vector<InputDeviceInfo::MotionRange>& ranges = deviceInfo.getMotionRanges();
     if (!ranges.isEmpty()) {
-        dump.append(INDENT2 "Motion Ranges:\n");
+        dump += INDENT2 "Motion Ranges:\n";
         for (size_t i = 0; i < ranges.size(); i++) {
             const InputDeviceInfo::MotionRange& range = ranges.itemAt(i);
             const char* label = getAxisLabel(range.axis);
@@ -1094,7 +1097,7 @@
             } else {
                 snprintf(name, sizeof(name), "%d", range.axis);
             }
-            dump.appendFormat(INDENT3 "%s: source=0x%08x, "
+            dump += StringPrintf(INDENT3 "%s: source=0x%08x, "
                     "min=%0.3f, max=%0.3f, flat=%0.3f, fuzz=%0.3f, resolution=%0.3f\n",
                     name, range.source, range.min, range.max, range.flat, range.fuzz,
                     range.resolution);
@@ -1982,7 +1985,7 @@
     info->addSource(getSources());
 }
 
-void InputMapper::dump(String8& dump) {
+void InputMapper::dump(std::string& dump) {
 }
 
 void InputMapper::configure(nsecs_t when,
@@ -2044,21 +2047,21 @@
     mDevice->bumpGeneration();
 }
 
-void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump,
+void InputMapper::dumpRawAbsoluteAxisInfo(std::string& dump,
         const RawAbsoluteAxisInfo& axis, const char* name) {
     if (axis.valid) {
-        dump.appendFormat(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n",
+        dump += StringPrintf(INDENT4 "%s: min=%d, max=%d, flat=%d, fuzz=%d, resolution=%d\n",
                 name, axis.minValue, axis.maxValue, axis.flat, axis.fuzz, axis.resolution);
     } else {
-        dump.appendFormat(INDENT4 "%s: unknown range\n", name);
+        dump += StringPrintf(INDENT4 "%s: unknown range\n", name);
     }
 }
 
-void InputMapper::dumpStylusState(String8& dump, const StylusState& state) {
-    dump.appendFormat(INDENT4 "When: %" PRId64 "\n", state.when);
-    dump.appendFormat(INDENT4 "Pressure: %f\n", state.pressure);
-    dump.appendFormat(INDENT4 "Button State: 0x%08x\n", state.buttons);
-    dump.appendFormat(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType);
+void InputMapper::dumpStylusState(std::string& dump, const StylusState& state) {
+    dump += StringPrintf(INDENT4 "When: %" PRId64 "\n", state.when);
+    dump += StringPrintf(INDENT4 "Pressure: %f\n", state.pressure);
+    dump += StringPrintf(INDENT4 "Button State: 0x%08x\n", state.buttons);
+    dump += StringPrintf(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType);
 }
 
 // --- SwitchInputMapper ---
@@ -2112,9 +2115,9 @@
     return getEventHub()->getSwitchState(getDeviceId(), switchCode);
 }
 
-void SwitchInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Switch Input Mapper:\n");
-    dump.appendFormat(INDENT3 "SwitchValues: %x\n", mSwitchValues);
+void SwitchInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "Switch Input Mapper:\n";
+    dump += StringPrintf(INDENT3 "SwitchValues: %x\n", mSwitchValues);
 }
 
 // --- VibratorInputMapper ---
@@ -2143,15 +2146,15 @@
 void VibratorInputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
         int32_t token) {
 #if DEBUG_VIBRATOR
-    String8 patternStr;
+    std::string patternStr;
     for (size_t i = 0; i < patternSize; i++) {
         if (i != 0) {
-            patternStr.append(", ");
+            patternStr += ", ";
         }
-        patternStr.appendFormat("%" PRId64, pattern[i]);
+        patternStr += StringPrintf("%" PRId64, pattern[i]);
     }
     ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%zd, token=%d",
-            getDeviceId(), patternStr.string(), repeat, token);
+            getDeviceId(), patternStr.c_str(), repeat, token);
 #endif
 
     mVibrating = true;
@@ -2224,9 +2227,9 @@
     getEventHub()->cancelVibrate(getDeviceId());
 }
 
-void VibratorInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Vibrator Input Mapper:\n");
-    dump.appendFormat(INDENT3 "Vibrating: %s\n", toString(mVibrating));
+void VibratorInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "Vibrator Input Mapper:\n";
+    dump += StringPrintf(INDENT3 "Vibrating: %s\n", toString(mVibrating));
 }
 
 
@@ -2252,14 +2255,14 @@
     info->setKeyCharacterMap(getEventHub()->getKeyCharacterMap(getDeviceId()));
 }
 
-void KeyboardInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Keyboard Input Mapper:\n");
+void KeyboardInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "Keyboard Input Mapper:\n";
     dumpParameters(dump);
-    dump.appendFormat(INDENT3 "KeyboardType: %d\n", mKeyboardType);
-    dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation);
-    dump.appendFormat(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size());
-    dump.appendFormat(INDENT3 "MetaState: 0x%0x\n", mMetaState);
-    dump.appendFormat(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
+    dump += StringPrintf(INDENT3 "KeyboardType: %d\n", mKeyboardType);
+    dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation);
+    dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size());
+    dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState);
+    dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
 }
 
 
@@ -2319,13 +2322,13 @@
             mParameters.handlesKeyRepeat);
 }
 
-void KeyboardInputMapper::dumpParameters(String8& dump) {
-    dump.append(INDENT3 "Parameters:\n");
-    dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
+void KeyboardInputMapper::dumpParameters(std::string& dump) {
+    dump += INDENT3 "Parameters:\n";
+    dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n",
             toString(mParameters.hasAssociatedDisplay));
-    dump.appendFormat(INDENT4 "OrientationAware: %s\n",
+    dump += StringPrintf(INDENT4 "OrientationAware: %s\n",
             toString(mParameters.orientationAware));
-    dump.appendFormat(INDENT4 "HandlesKeyRepeat: %s\n",
+    dump += StringPrintf(INDENT4 "HandlesKeyRepeat: %s\n",
             toString(mParameters.handlesKeyRepeat));
 }
 
@@ -2604,23 +2607,23 @@
     }
 }
 
-void CursorInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Cursor Input Mapper:\n");
+void CursorInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "Cursor Input Mapper:\n";
     dumpParameters(dump);
-    dump.appendFormat(INDENT3 "XScale: %0.3f\n", mXScale);
-    dump.appendFormat(INDENT3 "YScale: %0.3f\n", mYScale);
-    dump.appendFormat(INDENT3 "XPrecision: %0.3f\n", mXPrecision);
-    dump.appendFormat(INDENT3 "YPrecision: %0.3f\n", mYPrecision);
-    dump.appendFormat(INDENT3 "HaveVWheel: %s\n",
+    dump += StringPrintf(INDENT3 "XScale: %0.3f\n", mXScale);
+    dump += StringPrintf(INDENT3 "YScale: %0.3f\n", mYScale);
+    dump += StringPrintf(INDENT3 "XPrecision: %0.3f\n", mXPrecision);
+    dump += StringPrintf(INDENT3 "YPrecision: %0.3f\n", mYPrecision);
+    dump += StringPrintf(INDENT3 "HaveVWheel: %s\n",
             toString(mCursorScrollAccumulator.haveRelativeVWheel()));
-    dump.appendFormat(INDENT3 "HaveHWheel: %s\n",
+    dump += StringPrintf(INDENT3 "HaveHWheel: %s\n",
             toString(mCursorScrollAccumulator.haveRelativeHWheel()));
-    dump.appendFormat(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
-    dump.appendFormat(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
-    dump.appendFormat(INDENT3 "Orientation: %d\n", mOrientation);
-    dump.appendFormat(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
-    dump.appendFormat(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState)));
-    dump.appendFormat(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
+    dump += StringPrintf(INDENT3 "VWheelScale: %0.3f\n", mVWheelScale);
+    dump += StringPrintf(INDENT3 "HWheelScale: %0.3f\n", mHWheelScale);
+    dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation);
+    dump += StringPrintf(INDENT3 "ButtonState: 0x%08x\n", mButtonState);
+    dump += StringPrintf(INDENT3 "Down: %s\n", toString(isPointerDown(mButtonState)));
+    dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
 }
 
 void CursorInputMapper::configure(nsecs_t when,
@@ -2728,26 +2731,26 @@
     }
 }
 
-void CursorInputMapper::dumpParameters(String8& dump) {
-    dump.append(INDENT3 "Parameters:\n");
-    dump.appendFormat(INDENT4 "HasAssociatedDisplay: %s\n",
+void CursorInputMapper::dumpParameters(std::string& dump) {
+    dump += INDENT3 "Parameters:\n";
+    dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n",
             toString(mParameters.hasAssociatedDisplay));
 
     switch (mParameters.mode) {
     case Parameters::MODE_POINTER:
-        dump.append(INDENT4 "Mode: pointer\n");
+        dump += INDENT4 "Mode: pointer\n";
         break;
     case Parameters::MODE_POINTER_RELATIVE:
-        dump.append(INDENT4 "Mode: relative pointer\n");
+        dump += INDENT4 "Mode: relative pointer\n";
         break;
     case Parameters::MODE_NAVIGATION:
-        dump.append(INDENT4 "Mode: navigation\n");
+        dump += INDENT4 "Mode: navigation\n";
         break;
     default:
         ALOG_ASSERT(false);
     }
 
-    dump.appendFormat(INDENT4 "OrientationAware: %s\n",
+    dump += StringPrintf(INDENT4 "OrientationAware: %s\n",
             toString(mParameters.orientationAware));
 }
 
@@ -3000,9 +3003,9 @@
     }
 }
 
-void RotaryEncoderInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Rotary Encoder Input Mapper:\n");
-    dump.appendFormat(INDENT3 "HaveWheel: %s\n",
+void RotaryEncoderInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "Rotary Encoder Input Mapper:\n";
+    dump += StringPrintf(INDENT3 "HaveWheel: %s\n",
             toString(mRotaryEncoderScrollAccumulator.haveRelativeVWheel()));
 }
 
@@ -3151,8 +3154,8 @@
     }
 }
 
-void TouchInputMapper::dump(String8& dump) {
-    dump.appendFormat(INDENT2 "Touch Input Mapper (mode - %s):\n", modeToString(mDeviceMode));
+void TouchInputMapper::dump(std::string& dump) {
+    dump += StringPrintf(INDENT2 "Touch Input Mapper (mode - %s):\n", modeToString(mDeviceMode));
     dumpParameters(dump);
     dumpVirtualKeys(dump);
     dumpRawPointerAxes(dump);
@@ -3160,30 +3163,30 @@
     dumpAffineTransformation(dump);
     dumpSurface(dump);
 
-    dump.appendFormat(INDENT3 "Translation and Scaling Factors:\n");
-    dump.appendFormat(INDENT4 "XTranslate: %0.3f\n", mXTranslate);
-    dump.appendFormat(INDENT4 "YTranslate: %0.3f\n", mYTranslate);
-    dump.appendFormat(INDENT4 "XScale: %0.3f\n", mXScale);
-    dump.appendFormat(INDENT4 "YScale: %0.3f\n", mYScale);
-    dump.appendFormat(INDENT4 "XPrecision: %0.3f\n", mXPrecision);
-    dump.appendFormat(INDENT4 "YPrecision: %0.3f\n", mYPrecision);
-    dump.appendFormat(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale);
-    dump.appendFormat(INDENT4 "PressureScale: %0.3f\n", mPressureScale);
-    dump.appendFormat(INDENT4 "SizeScale: %0.3f\n", mSizeScale);
-    dump.appendFormat(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale);
-    dump.appendFormat(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale);
-    dump.appendFormat(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt));
-    dump.appendFormat(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter);
-    dump.appendFormat(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale);
-    dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter);
-    dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale);
+    dump += StringPrintf(INDENT3 "Translation and Scaling Factors:\n");
+    dump += StringPrintf(INDENT4 "XTranslate: %0.3f\n", mXTranslate);
+    dump += StringPrintf(INDENT4 "YTranslate: %0.3f\n", mYTranslate);
+    dump += StringPrintf(INDENT4 "XScale: %0.3f\n", mXScale);
+    dump += StringPrintf(INDENT4 "YScale: %0.3f\n", mYScale);
+    dump += StringPrintf(INDENT4 "XPrecision: %0.3f\n", mXPrecision);
+    dump += StringPrintf(INDENT4 "YPrecision: %0.3f\n", mYPrecision);
+    dump += StringPrintf(INDENT4 "GeometricScale: %0.3f\n", mGeometricScale);
+    dump += StringPrintf(INDENT4 "PressureScale: %0.3f\n", mPressureScale);
+    dump += StringPrintf(INDENT4 "SizeScale: %0.3f\n", mSizeScale);
+    dump += StringPrintf(INDENT4 "OrientationScale: %0.3f\n", mOrientationScale);
+    dump += StringPrintf(INDENT4 "DistanceScale: %0.3f\n", mDistanceScale);
+    dump += StringPrintf(INDENT4 "HaveTilt: %s\n", toString(mHaveTilt));
+    dump += StringPrintf(INDENT4 "TiltXCenter: %0.3f\n", mTiltXCenter);
+    dump += StringPrintf(INDENT4 "TiltXScale: %0.3f\n", mTiltXScale);
+    dump += StringPrintf(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter);
+    dump += StringPrintf(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale);
 
-    dump.appendFormat(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState);
-    dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n",
+    dump += StringPrintf(INDENT3 "Last Raw Button State: 0x%08x\n", mLastRawState.buttonState);
+    dump += StringPrintf(INDENT3 "Last Raw Touch: pointerCount=%d\n",
             mLastRawState.rawPointerData.pointerCount);
     for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) {
         const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i];
-        dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
+        dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, "
                 "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, "
                 "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, "
                 "toolType=%d, isHovering=%s\n", i,
@@ -3194,14 +3197,14 @@
                 pointer.toolType, toString(pointer.isHovering));
     }
 
-    dump.appendFormat(INDENT3 "Last Cooked Button State: 0x%08x\n", mLastCookedState.buttonState);
-    dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n",
+    dump += StringPrintf(INDENT3 "Last Cooked Button State: 0x%08x\n", mLastCookedState.buttonState);
+    dump += StringPrintf(INDENT3 "Last Cooked Touch: pointerCount=%d\n",
             mLastCookedState.cookedPointerData.pointerCount);
     for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) {
         const PointerProperties& pointerProperties =
                 mLastCookedState.cookedPointerData.pointerProperties[i];
         const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i];
-        dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, "
+        dump += StringPrintf(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, "
                 "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, "
                 "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, "
                 "toolType=%d, isHovering=%s\n", i,
@@ -3220,26 +3223,26 @@
                 toString(mLastCookedState.cookedPointerData.isHovering(i)));
     }
 
-    dump.append(INDENT3 "Stylus Fusion:\n");
-    dump.appendFormat(INDENT4 "ExternalStylusConnected: %s\n",
+    dump += INDENT3 "Stylus Fusion:\n";
+    dump += StringPrintf(INDENT4 "ExternalStylusConnected: %s\n",
             toString(mExternalStylusConnected));
-    dump.appendFormat(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId);
-    dump.appendFormat(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n",
+    dump += StringPrintf(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId);
+    dump += StringPrintf(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n",
             mExternalStylusFusionTimeout);
-    dump.append(INDENT3 "External Stylus State:\n");
+    dump += INDENT3 "External Stylus State:\n";
     dumpStylusState(dump, mExternalStylusState);
 
     if (mDeviceMode == DEVICE_MODE_POINTER) {
-        dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n");
-        dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n",
+        dump += StringPrintf(INDENT3 "Pointer Gesture Detector:\n");
+        dump += StringPrintf(INDENT4 "XMovementScale: %0.3f\n",
                 mPointerXMovementScale);
-        dump.appendFormat(INDENT4 "YMovementScale: %0.3f\n",
+        dump += StringPrintf(INDENT4 "YMovementScale: %0.3f\n",
                 mPointerYMovementScale);
-        dump.appendFormat(INDENT4 "XZoomScale: %0.3f\n",
+        dump += StringPrintf(INDENT4 "XZoomScale: %0.3f\n",
                 mPointerXZoomScale);
-        dump.appendFormat(INDENT4 "YZoomScale: %0.3f\n",
+        dump += StringPrintf(INDENT4 "YZoomScale: %0.3f\n",
                 mPointerYZoomScale);
-        dump.appendFormat(INDENT4 "MaxSwipeWidth: %f\n",
+        dump += StringPrintf(INDENT4 "MaxSwipeWidth: %f\n",
                 mPointerGestureMaxSwipeWidth);
     }
 }
@@ -3400,15 +3403,15 @@
             mParameters.wake);
 }
 
-void TouchInputMapper::dumpParameters(String8& dump) {
-    dump.append(INDENT3 "Parameters:\n");
+void TouchInputMapper::dumpParameters(std::string& dump) {
+    dump += INDENT3 "Parameters:\n";
 
     switch (mParameters.gestureMode) {
     case Parameters::GESTURE_MODE_SINGLE_TOUCH:
-        dump.append(INDENT4 "GestureMode: single-touch\n");
+        dump += INDENT4 "GestureMode: single-touch\n";
         break;
     case Parameters::GESTURE_MODE_MULTI_TOUCH:
-        dump.append(INDENT4 "GestureMode: multi-touch\n");
+        dump += INDENT4 "GestureMode: multi-touch\n";
         break;
     default:
         assert(false);
@@ -3416,27 +3419,27 @@
 
     switch (mParameters.deviceType) {
     case Parameters::DEVICE_TYPE_TOUCH_SCREEN:
-        dump.append(INDENT4 "DeviceType: touchScreen\n");
+        dump += INDENT4 "DeviceType: touchScreen\n";
         break;
     case Parameters::DEVICE_TYPE_TOUCH_PAD:
-        dump.append(INDENT4 "DeviceType: touchPad\n");
+        dump += INDENT4 "DeviceType: touchPad\n";
         break;
     case Parameters::DEVICE_TYPE_TOUCH_NAVIGATION:
-        dump.append(INDENT4 "DeviceType: touchNavigation\n");
+        dump += INDENT4 "DeviceType: touchNavigation\n";
         break;
     case Parameters::DEVICE_TYPE_POINTER:
-        dump.append(INDENT4 "DeviceType: pointer\n");
+        dump += INDENT4 "DeviceType: pointer\n";
         break;
     default:
         ALOG_ASSERT(false);
     }
 
-    dump.appendFormat(
+    dump += StringPrintf(
             INDENT4 "AssociatedDisplay: hasAssociatedDisplay=%s, isExternal=%s, displayId='%s'\n",
             toString(mParameters.hasAssociatedDisplay),
             toString(mParameters.associatedDisplayIsExternal),
             mParameters.uniqueDisplayId.c_str());
-    dump.appendFormat(INDENT4 "OrientationAware: %s\n",
+    dump += StringPrintf(INDENT4 "OrientationAware: %s\n",
             toString(mParameters.orientationAware));
 }
 
@@ -3444,8 +3447,8 @@
     mRawPointerAxes.clear();
 }
 
-void TouchInputMapper::dumpRawPointerAxes(String8& dump) {
-    dump.append(INDENT3 "Raw Touch Axes:\n");
+void TouchInputMapper::dumpRawPointerAxes(std::string& dump) {
+    dump += INDENT3 "Raw Touch Axes:\n";
     dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.x, "X");
     dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.y, "Y");
     dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.pressure, "Pressure");
@@ -3702,11 +3705,13 @@
 
         // Pressure factors.
         mPressureScale = 0;
+        float pressureMax = 1.0;
         if (mCalibration.pressureCalibration == Calibration::PRESSURE_CALIBRATION_PHYSICAL
                 || mCalibration.pressureCalibration
                         == Calibration::PRESSURE_CALIBRATION_AMPLITUDE) {
             if (mCalibration.havePressureScale) {
                 mPressureScale = mCalibration.pressureScale;
+                pressureMax = mPressureScale * mRawPointerAxes.pressure.maxValue;
             } else if (mRawPointerAxes.pressure.valid
                     && mRawPointerAxes.pressure.maxValue != 0) {
                 mPressureScale = 1.0f / mRawPointerAxes.pressure.maxValue;
@@ -3716,7 +3721,7 @@
         mOrientedRanges.pressure.axis = AMOTION_EVENT_AXIS_PRESSURE;
         mOrientedRanges.pressure.source = mSource;
         mOrientedRanges.pressure.min = 0;
-        mOrientedRanges.pressure.max = 1.0;
+        mOrientedRanges.pressure.max = pressureMax;
         mOrientedRanges.pressure.flat = 0;
         mOrientedRanges.pressure.fuzz = 0;
         mOrientedRanges.pressure.resolution = 0;
@@ -3890,8 +3895,8 @@
     }
 }
 
-void TouchInputMapper::dumpSurface(String8& dump) {
-    dump.appendFormat(INDENT3 "Viewport: displayId=%d, orientation=%d, "
+void TouchInputMapper::dumpSurface(std::string& dump) {
+    dump += StringPrintf(INDENT3 "Viewport: displayId=%d, orientation=%d, "
             "logicalFrame=[%d, %d, %d, %d], "
             "physicalFrame=[%d, %d, %d, %d], "
             "deviceSize=[%d, %d]\n",
@@ -3902,11 +3907,11 @@
             mViewport.physicalRight, mViewport.physicalBottom,
             mViewport.deviceWidth, mViewport.deviceHeight);
 
-    dump.appendFormat(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth);
-    dump.appendFormat(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight);
-    dump.appendFormat(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
-    dump.appendFormat(INDENT3 "SurfaceTop: %d\n", mSurfaceTop);
-    dump.appendFormat(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation);
+    dump += StringPrintf(INDENT3 "SurfaceWidth: %dpx\n", mSurfaceWidth);
+    dump += StringPrintf(INDENT3 "SurfaceHeight: %dpx\n", mSurfaceHeight);
+    dump += StringPrintf(INDENT3 "SurfaceLeft: %d\n", mSurfaceLeft);
+    dump += StringPrintf(INDENT3 "SurfaceTop: %d\n", mSurfaceTop);
+    dump += StringPrintf(INDENT3 "SurfaceOrientation: %d\n", mSurfaceOrientation);
 }
 
 void TouchInputMapper::configureVirtualKeys() {
@@ -3963,13 +3968,13 @@
     }
 }
 
-void TouchInputMapper::dumpVirtualKeys(String8& dump) {
+void TouchInputMapper::dumpVirtualKeys(std::string& dump) {
     if (!mVirtualKeys.isEmpty()) {
-        dump.append(INDENT3 "Virtual Keys:\n");
+        dump += INDENT3 "Virtual Keys:\n";
 
         for (size_t i = 0; i < mVirtualKeys.size(); i++) {
             const VirtualKey& virtualKey = mVirtualKeys.itemAt(i);
-            dump.appendFormat(INDENT4 "%zu: scanCode=%d, keyCode=%d, "
+            dump += StringPrintf(INDENT4 "%zu: scanCode=%d, keyCode=%d, "
                     "hitLeft=%d, hitRight=%d, hitTop=%d, hitBottom=%d\n",
                     i, virtualKey.scanCode, virtualKey.keyCode,
                     virtualKey.hitLeft, virtualKey.hitRight,
@@ -4118,75 +4123,75 @@
     }
 }
 
-void TouchInputMapper::dumpCalibration(String8& dump) {
-    dump.append(INDENT3 "Calibration:\n");
+void TouchInputMapper::dumpCalibration(std::string& dump) {
+    dump += INDENT3 "Calibration:\n";
 
     // Size
     switch (mCalibration.sizeCalibration) {
     case Calibration::SIZE_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.size.calibration: none\n");
+        dump += INDENT4 "touch.size.calibration: none\n";
         break;
     case Calibration::SIZE_CALIBRATION_GEOMETRIC:
-        dump.append(INDENT4 "touch.size.calibration: geometric\n");
+        dump += INDENT4 "touch.size.calibration: geometric\n";
         break;
     case Calibration::SIZE_CALIBRATION_DIAMETER:
-        dump.append(INDENT4 "touch.size.calibration: diameter\n");
+        dump += INDENT4 "touch.size.calibration: diameter\n";
         break;
     case Calibration::SIZE_CALIBRATION_BOX:
-        dump.append(INDENT4 "touch.size.calibration: box\n");
+        dump += INDENT4 "touch.size.calibration: box\n";
         break;
     case Calibration::SIZE_CALIBRATION_AREA:
-        dump.append(INDENT4 "touch.size.calibration: area\n");
+        dump += INDENT4 "touch.size.calibration: area\n";
         break;
     default:
         ALOG_ASSERT(false);
     }
 
     if (mCalibration.haveSizeScale) {
-        dump.appendFormat(INDENT4 "touch.size.scale: %0.3f\n",
+        dump += StringPrintf(INDENT4 "touch.size.scale: %0.3f\n",
                 mCalibration.sizeScale);
     }
 
     if (mCalibration.haveSizeBias) {
-        dump.appendFormat(INDENT4 "touch.size.bias: %0.3f\n",
+        dump += StringPrintf(INDENT4 "touch.size.bias: %0.3f\n",
                 mCalibration.sizeBias);
     }
 
     if (mCalibration.haveSizeIsSummed) {
-        dump.appendFormat(INDENT4 "touch.size.isSummed: %s\n",
+        dump += StringPrintf(INDENT4 "touch.size.isSummed: %s\n",
                 toString(mCalibration.sizeIsSummed));
     }
 
     // Pressure
     switch (mCalibration.pressureCalibration) {
     case Calibration::PRESSURE_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.pressure.calibration: none\n");
+        dump += INDENT4 "touch.pressure.calibration: none\n";
         break;
     case Calibration::PRESSURE_CALIBRATION_PHYSICAL:
-        dump.append(INDENT4 "touch.pressure.calibration: physical\n");
+        dump += INDENT4 "touch.pressure.calibration: physical\n";
         break;
     case Calibration::PRESSURE_CALIBRATION_AMPLITUDE:
-        dump.append(INDENT4 "touch.pressure.calibration: amplitude\n");
+        dump += INDENT4 "touch.pressure.calibration: amplitude\n";
         break;
     default:
         ALOG_ASSERT(false);
     }
 
     if (mCalibration.havePressureScale) {
-        dump.appendFormat(INDENT4 "touch.pressure.scale: %0.3f\n",
+        dump += StringPrintf(INDENT4 "touch.pressure.scale: %0.3f\n",
                 mCalibration.pressureScale);
     }
 
     // Orientation
     switch (mCalibration.orientationCalibration) {
     case Calibration::ORIENTATION_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.orientation.calibration: none\n");
+        dump += INDENT4 "touch.orientation.calibration: none\n";
         break;
     case Calibration::ORIENTATION_CALIBRATION_INTERPOLATED:
-        dump.append(INDENT4 "touch.orientation.calibration: interpolated\n");
+        dump += INDENT4 "touch.orientation.calibration: interpolated\n";
         break;
     case Calibration::ORIENTATION_CALIBRATION_VECTOR:
-        dump.append(INDENT4 "touch.orientation.calibration: vector\n");
+        dump += INDENT4 "touch.orientation.calibration: vector\n";
         break;
     default:
         ALOG_ASSERT(false);
@@ -4195,41 +4200,41 @@
     // Distance
     switch (mCalibration.distanceCalibration) {
     case Calibration::DISTANCE_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.distance.calibration: none\n");
+        dump += INDENT4 "touch.distance.calibration: none\n";
         break;
     case Calibration::DISTANCE_CALIBRATION_SCALED:
-        dump.append(INDENT4 "touch.distance.calibration: scaled\n");
+        dump += INDENT4 "touch.distance.calibration: scaled\n";
         break;
     default:
         ALOG_ASSERT(false);
     }
 
     if (mCalibration.haveDistanceScale) {
-        dump.appendFormat(INDENT4 "touch.distance.scale: %0.3f\n",
+        dump += StringPrintf(INDENT4 "touch.distance.scale: %0.3f\n",
                 mCalibration.distanceScale);
     }
 
     switch (mCalibration.coverageCalibration) {
     case Calibration::COVERAGE_CALIBRATION_NONE:
-        dump.append(INDENT4 "touch.coverage.calibration: none\n");
+        dump += INDENT4 "touch.coverage.calibration: none\n";
         break;
     case Calibration::COVERAGE_CALIBRATION_BOX:
-        dump.append(INDENT4 "touch.coverage.calibration: box\n");
+        dump += INDENT4 "touch.coverage.calibration: box\n";
         break;
     default:
         ALOG_ASSERT(false);
     }
 }
 
-void TouchInputMapper::dumpAffineTransformation(String8& dump) {
-    dump.append(INDENT3 "Affine Transformation:\n");
+void TouchInputMapper::dumpAffineTransformation(std::string& dump) {
+    dump += INDENT3 "Affine Transformation:\n";
 
-    dump.appendFormat(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale);
-    dump.appendFormat(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix);
-    dump.appendFormat(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset);
-    dump.appendFormat(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix);
-    dump.appendFormat(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale);
-    dump.appendFormat(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset);
+    dump += StringPrintf(INDENT4 "X scale: %0.3f\n", mAffineTransform.x_scale);
+    dump += StringPrintf(INDENT4 "X ymix: %0.3f\n", mAffineTransform.x_ymix);
+    dump += StringPrintf(INDENT4 "X offset: %0.3f\n", mAffineTransform.x_offset);
+    dump += StringPrintf(INDENT4 "Y xmix: %0.3f\n", mAffineTransform.y_xmix);
+    dump += StringPrintf(INDENT4 "Y scale: %0.3f\n", mAffineTransform.y_scale);
+    dump += StringPrintf(INDENT4 "Y offset: %0.3f\n", mAffineTransform.y_offset);
 }
 
 void TouchInputMapper::updateAffineTransformation() {
@@ -7005,11 +7010,11 @@
             0.0f, 1.0f, 0.0f, 0.0f, 0.0f);
 }
 
-void ExternalStylusInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "External Stylus Input Mapper:\n");
-    dump.append(INDENT3 "Raw Stylus Axes:\n");
+void ExternalStylusInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "External Stylus Input Mapper:\n";
+    dump += INDENT3 "Raw Stylus Axes:\n";
     dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure");
-    dump.append(INDENT3 "Stylus State:\n");
+    dump += INDENT3 "Stylus State:\n";
     dumpStylusState(dump, mStylusState);
 }
 
@@ -7114,37 +7119,37 @@
     return -1;
 }
 
-void JoystickInputMapper::dump(String8& dump) {
-    dump.append(INDENT2 "Joystick Input Mapper:\n");
+void JoystickInputMapper::dump(std::string& dump) {
+    dump += INDENT2 "Joystick Input Mapper:\n";
 
-    dump.append(INDENT3 "Axes:\n");
+    dump += INDENT3 "Axes:\n";
     size_t numAxes = mAxes.size();
     for (size_t i = 0; i < numAxes; i++) {
         const Axis& axis = mAxes.valueAt(i);
         const char* label = getAxisLabel(axis.axisInfo.axis);
         if (label) {
-            dump.appendFormat(INDENT4 "%s", label);
+            dump += StringPrintf(INDENT4 "%s", label);
         } else {
-            dump.appendFormat(INDENT4 "%d", axis.axisInfo.axis);
+            dump += StringPrintf(INDENT4 "%d", axis.axisInfo.axis);
         }
         if (axis.axisInfo.mode == AxisInfo::MODE_SPLIT) {
             label = getAxisLabel(axis.axisInfo.highAxis);
             if (label) {
-                dump.appendFormat(" / %s (split at %d)", label, axis.axisInfo.splitValue);
+                dump += StringPrintf(" / %s (split at %d)", label, axis.axisInfo.splitValue);
             } else {
-                dump.appendFormat(" / %d (split at %d)", axis.axisInfo.highAxis,
+                dump += StringPrintf(" / %d (split at %d)", axis.axisInfo.highAxis,
                         axis.axisInfo.splitValue);
             }
         } else if (axis.axisInfo.mode == AxisInfo::MODE_INVERT) {
-            dump.append(" (invert)");
+            dump += " (invert)";
         }
 
-        dump.appendFormat(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n",
+        dump += StringPrintf(": min=%0.5f, max=%0.5f, flat=%0.5f, fuzz=%0.5f, resolution=%0.5f\n",
                 axis.min, axis.max, axis.flat, axis.fuzz, axis.resolution);
-        dump.appendFormat(INDENT4 "  scale=%0.5f, offset=%0.5f, "
+        dump += StringPrintf(INDENT4 "  scale=%0.5f, offset=%0.5f, "
                 "highScale=%0.5f, highOffset=%0.5f\n",
                 axis.scale, axis.offset, axis.highScale, axis.highOffset);
-        dump.appendFormat(INDENT4 "  rawAxis=%d, rawMin=%d, rawMax=%d, "
+        dump += StringPrintf(INDENT4 "  rawAxis=%d, rawMin=%d, rawMax=%d, "
                 "rawFlat=%d, rawFuzz=%d, rawResolution=%d\n",
                 mAxes.keyAt(i), axis.rawAxisInfo.minValue, axis.rawAxisInfo.maxValue,
                 axis.rawAxisInfo.flat, axis.rawAxisInfo.fuzz, axis.rawAxisInfo.resolution);
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index a6b9798..4f48262 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -32,7 +32,6 @@
 #include <utils/Mutex.h>
 #include <utils/Timers.h>
 #include <utils/RefBase.h>
-#include <utils/String8.h>
 #include <utils/BitSet.h>
 #include <utils/SortedVector.h>
 
@@ -207,8 +206,8 @@
     void setVirtualDisplayViewports(const Vector<DisplayViewport>& viewports);
 
 
-    void dump(String8& dump) const;
-    void dumpViewport(String8& dump, const DisplayViewport& viewport) const;
+    void dump(std::string& dump) const;
+    void dumpViewport(std::string& dump, const DisplayViewport& viewport) const;
 
 private:
     DisplayViewport mInternalDisplay;
@@ -292,7 +291,7 @@
     /* Dumps the state of the input reader.
      *
      * This method may be called on any thread (usually by the input manager). */
-    virtual void dump(String8& dump) = 0;
+    virtual void dump(std::string& dump) = 0;
 
     /* Called by the heatbeat to ensures that the reader has not deadlocked. */
     virtual void monitor() = 0;
@@ -412,7 +411,7 @@
             const sp<InputListenerInterface>& listener);
     virtual ~InputReader();
 
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void monitor();
 
     virtual void loopOnce();
@@ -569,7 +568,7 @@
     bool isEnabled();
     void setEnabled(bool enabled, nsecs_t when);
 
-    void dump(String8& dump);
+    void dump(std::string& dump);
     void addMapper(InputMapper* mapper);
     void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     void reset(nsecs_t when);
@@ -987,7 +986,7 @@
 
     virtual uint32_t getSources() = 0;
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     virtual void reset(nsecs_t when);
     virtual void process(const RawEvent* rawEvent) = 0;
@@ -1017,9 +1016,9 @@
     status_t getAbsoluteAxisInfo(int32_t axis, RawAbsoluteAxisInfo* axisInfo);
     void bumpGeneration();
 
-    static void dumpRawAbsoluteAxisInfo(String8& dump,
+    static void dumpRawAbsoluteAxisInfo(std::string& dump,
             const RawAbsoluteAxisInfo& axis, const char* name);
-    static void dumpStylusState(String8& dump, const StylusState& state);
+    static void dumpStylusState(std::string& dump, const StylusState& state);
 };
 
 
@@ -1032,7 +1031,7 @@
     virtual void process(const RawEvent* rawEvent);
 
     virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
 
 private:
     uint32_t mSwitchValues;
@@ -1056,7 +1055,7 @@
             int32_t token);
     virtual void cancelVibrate(int32_t token);
     virtual void timeoutExpired(nsecs_t when);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
 
 private:
     bool mVibrating;
@@ -1079,7 +1078,7 @@
 
     virtual uint32_t getSources();
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     virtual void reset(nsecs_t when);
     virtual void process(const RawEvent* rawEvent);
@@ -1125,7 +1124,7 @@
     } mParameters;
 
     void configureParameters();
-    void dumpParameters(String8& dump);
+    void dumpParameters(std::string& dump);
 
     bool isKeyboardOrGamepadKey(int32_t scanCode);
     bool isMediaKey(int32_t keyCode);
@@ -1151,7 +1150,7 @@
 
     virtual uint32_t getSources();
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     virtual void reset(nsecs_t when);
     virtual void process(const RawEvent* rawEvent);
@@ -1204,7 +1203,7 @@
     nsecs_t mDownTime;
 
     void configureParameters();
-    void dumpParameters(String8& dump);
+    void dumpParameters(std::string& dump);
 
     void sync(nsecs_t when);
 };
@@ -1217,7 +1216,7 @@
 
     virtual uint32_t getSources();
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     virtual void reset(nsecs_t when);
     virtual void process(const RawEvent* rawEvent);
@@ -1239,7 +1238,7 @@
 
     virtual uint32_t getSources();
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     virtual void reset(nsecs_t when);
     virtual void process(const RawEvent* rawEvent);
@@ -1482,18 +1481,18 @@
     Vector<VirtualKey> mVirtualKeys;
 
     virtual void configureParameters();
-    virtual void dumpParameters(String8& dump);
+    virtual void dumpParameters(std::string& dump);
     virtual void configureRawPointerAxes();
-    virtual void dumpRawPointerAxes(String8& dump);
+    virtual void dumpRawPointerAxes(std::string& dump);
     virtual void configureSurface(nsecs_t when, bool* outResetNeeded);
-    virtual void dumpSurface(String8& dump);
+    virtual void dumpSurface(std::string& dump);
     virtual void configureVirtualKeys();
-    virtual void dumpVirtualKeys(String8& dump);
+    virtual void dumpVirtualKeys(std::string& dump);
     virtual void parseCalibration();
     virtual void resolveCalibration();
-    virtual void dumpCalibration(String8& dump);
+    virtual void dumpCalibration(std::string& dump);
     virtual void updateAffineTransformation();
-    virtual void dumpAffineTransformation(String8& dump);
+    virtual void dumpAffineTransformation(std::string& dump);
     virtual void resolveExternalStylusPresence();
     virtual bool hasStylus() const = 0;
     virtual bool hasExternalStylus() const;
@@ -1904,7 +1903,7 @@
 
     virtual uint32_t getSources();
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     virtual void reset(nsecs_t when);
     virtual void process(const RawEvent* rawEvent);
@@ -1926,7 +1925,7 @@
 
     virtual uint32_t getSources();
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo);
-    virtual void dump(String8& dump);
+    virtual void dump(std::string& dump);
     virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes);
     virtual void reset(nsecs_t when);
     virtual void process(const RawEvent* rawEvent);
diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
index 9eb2798..5a48375 100644
--- a/services/inputflinger/InputWindow.h
+++ b/services/inputflinger/InputWindow.h
@@ -23,7 +23,6 @@
 #include <ui/Region.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
-#include <utils/String8.h>
 
 #include "InputApplication.h"
 
@@ -116,7 +115,7 @@
     };
 
     sp<InputChannel> inputChannel;
-    String8 name;
+    std::string name;
     int32_t layoutParamsFlags;
     int32_t layoutParamsType;
     nsecs_t dispatchingTimeout;
@@ -173,8 +172,8 @@
         return mInfo ? mInfo->inputChannel : NULL;
     }
 
-    inline String8 getName() const {
-        return mInfo ? mInfo->name : String8("<invalid>");
+    inline std::string getName() const {
+        return mInfo ? mInfo->name : "<invalid>";
     }
 
     inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 7ae36d8..aa6df24 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -54,7 +54,7 @@
 
     virtual nsecs_t notifyANR(const sp<InputApplicationHandle>&,
             const sp<InputWindowHandle>&,
-            const String8&) {
+            const std::string&) {
         return 0;
     }
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 76291a5..63c92d1 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -798,7 +798,7 @@
         return false;
     }
 
-    virtual void dump(String8&) {
+    virtual void dump(std::string&) {
     }
 
     virtual void monitor() {
@@ -2954,8 +2954,8 @@
 const int32_t TouchInputMapperTest::RAW_TOUCH_MAX = 31;
 const int32_t TouchInputMapperTest::RAW_TOOL_MIN = 0;
 const int32_t TouchInputMapperTest::RAW_TOOL_MAX = 15;
-const int32_t TouchInputMapperTest::RAW_PRESSURE_MIN = RAW_TOUCH_MIN;
-const int32_t TouchInputMapperTest::RAW_PRESSURE_MAX = RAW_TOUCH_MAX;
+const int32_t TouchInputMapperTest::RAW_PRESSURE_MIN = 0;
+const int32_t TouchInputMapperTest::RAW_PRESSURE_MAX = 255;
 const int32_t TouchInputMapperTest::RAW_ORIENTATION_MIN = -7;
 const int32_t TouchInputMapperTest::RAW_ORIENTATION_MAX = 7;
 const int32_t TouchInputMapperTest::RAW_DISTANCE_MIN = 0;
@@ -5316,6 +5316,12 @@
     addConfigurationProperty("touch.pressure.scale", "0.01");
     addMapperAndConfigure(mapper);
 
+    InputDeviceInfo info;
+    mapper->populateDeviceInfo(&info);
+    ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
+            AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_TOUCHSCREEN,
+            0.0f, RAW_PRESSURE_MAX * 0.01, 0.0f, 0.0f));
+
     // These calculations are based on the input device calibration documentation.
     int32_t rawX = 100;
     int32_t rawY = 200;
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index deead06..5b6c1ca 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -15,13 +15,13 @@
     GpuService.cpp \
     Layer.cpp \
     BufferLayer.cpp \
+    BufferLayerConsumer.cpp \
     ColorLayer.cpp \
     LayerRejecter.cpp \
     LayerVector.cpp \
     MessageQueue.cpp \
     MonitoredProducer.cpp \
     SurfaceFlinger.cpp \
-    SurfaceFlingerConsumer.cpp \
     SurfaceInterceptor.cpp \
     SurfaceTracing.cpp \
     Transform.cpp \
@@ -30,12 +30,12 @@
     DisplayHardware/HWC2.cpp \
     DisplayHardware/HWComposer.cpp \
     DisplayHardware/HWComposerBufferCache.cpp \
-    DisplayHardware/PowerHAL.cpp \
     DisplayHardware/VirtualDisplaySurface.cpp \
     Effects/Daltonizer.cpp \
     EventLog/EventLogTags.logtags \
     EventLog/EventLog.cpp \
     RenderEngine/Description.cpp \
+    RenderEngine/Image.cpp \
     RenderEngine/Mesh.cpp \
     RenderEngine/Program.cpp \
     RenderEngine/ProgramCache.cpp \
@@ -89,7 +89,6 @@
     libbinder \
     libui \
     libgui \
-    libpowermanager \
     libvulkan \
     libsync \
     libprotobuf-cpp-lite \
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 0d947b1..5f70ab5 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -53,7 +53,7 @@
 BufferLayer::BufferLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name,
                          uint32_t w, uint32_t h, uint32_t flags)
       : Layer(flinger, client, name, w, h, flags),
-        mSurfaceFlingerConsumer(nullptr),
+        mConsumer(nullptr),
         mTextureName(UINT32_MAX),
         mFormat(PIXEL_FORMAT_NONE),
         mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
@@ -75,17 +75,6 @@
 }
 
 BufferLayer::~BufferLayer() {
-    sp<Client> c(mClientRef.promote());
-    if (c != 0) {
-        c->detachLayer(this);
-    }
-
-    for (auto& point : mRemoteSyncPoints) {
-        point->setTransactionApplied();
-    }
-    for (auto& point : mLocalSyncPoints) {
-        point->setFrameAvailable();
-    }
     mFlinger->deleteTextureAsync(mTextureName);
 
     if (!getBE().mHwcLayers.empty()) {
@@ -100,7 +89,7 @@
     if (mFlinger->mForceFullDamage) {
         surfaceDamageRegion = Region::INVALID_REGION;
     } else {
-        surfaceDamageRegion = mSurfaceFlingerConsumer->getSurfaceDamage();
+        surfaceDamageRegion = mConsumer->getSurfaceDamage();
     }
 }
 
@@ -109,14 +98,14 @@
 }
 
 bool BufferLayer::isProtected() const {
-    const sp<GraphicBuffer>& buffer(getBE().mBuffer);
+    const sp<GraphicBuffer>& buffer(getBE().compositionInfo.mBuffer);
     return (buffer != 0) &&
             (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
 }
 
 bool BufferLayer::isVisible() const {
     return !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
-            (getBE().mBuffer != NULL || getBE().mSidebandStream != NULL);
+            (getBE().compositionInfo.mBuffer != NULL || getBE().compositionInfo.hwc.sidebandStream != NULL);
 }
 
 bool BufferLayer::isFixedSize() const {
@@ -140,9 +129,9 @@
     mProtectedByApp = (flags & ISurfaceComposerClient::eProtectedByApp) ? true : false;
     mCurrentOpacity = getOpacityForFormat(format);
 
-    mSurfaceFlingerConsumer->setDefaultBufferSize(w, h);
-    mSurfaceFlingerConsumer->setDefaultBufferFormat(format);
-    mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+    mConsumer->setDefaultBufferSize(w, h);
+    mConsumer->setDefaultBufferFormat(format);
+    mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
 
     return NO_ERROR;
 }
@@ -172,7 +161,7 @@
                          bool useIdentityTransform) const {
     ATRACE_CALL();
 
-    if (CC_UNLIKELY(getBE().mBuffer == 0)) {
+    if (CC_UNLIKELY(getBE().compositionInfo.mBuffer == 0)) {
         // the texture has not been created yet, this Layer has
         // in fact never been drawn into. This happens frequently with
         // SurfaceView because the WindowManager can't know when the client
@@ -201,7 +190,7 @@
 
     // Bind the current buffer to the GL texture, and wait for it to be
     // ready for us to draw into.
-    status_t err = mSurfaceFlingerConsumer->bindTextureImage();
+    status_t err = mConsumer->bindTextureImage();
     if (err != NO_ERROR) {
         ALOGW("onDraw: bindTextureImage failed (err=%d)", err);
         // Go ahead and draw the buffer anyway; no matter what we do the screen
@@ -218,8 +207,8 @@
 
         // Query the texture matrix given our current filtering mode.
         float textureMatrix[16];
-        mSurfaceFlingerConsumer->setFilteringEnabled(useFiltering);
-        mSurfaceFlingerConsumer->getTransformMatrix(textureMatrix);
+        mConsumer->setFilteringEnabled(useFiltering);
+        mConsumer->getTransformMatrix(textureMatrix);
 
         if (getTransformToDisplayInverse()) {
             /*
@@ -250,8 +239,8 @@
         }
 
         // Set things up for texturing.
-        mTexture.setDimensions(getBE().mBuffer->getWidth(),
-                               getBE().mBuffer->getHeight());
+        mTexture.setDimensions(getBE().compositionInfo.mBuffer->getWidth(),
+                               getBE().compositionInfo.mBuffer->getHeight());
         mTexture.setFiltering(useFiltering);
         mTexture.setMatrix(textureMatrix);
 
@@ -264,11 +253,11 @@
 }
 
 void BufferLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
-    mSurfaceFlingerConsumer->setReleaseFence(releaseFence);
+    mConsumer->setReleaseFence(releaseFence);
 }
 
 void BufferLayer::abandon() {
-    mSurfaceFlingerConsumer->abandon();
+    mConsumer->abandon();
 }
 
 bool BufferLayer::shouldPresentNow(const DispSync& dispSync) const {
@@ -281,7 +270,7 @@
         return false;
     }
     auto timestamp = mQueueItems[0].mTimestamp;
-    nsecs_t expectedPresent = mSurfaceFlingerConsumer->computeExpectedPresent(dispSync);
+    nsecs_t expectedPresent = mConsumer->computeExpectedPresent(dispSync);
 
     // Ignore timestamps more than a second in the future
     bool isPlausible = timestamp < (expectedPresent + s2ns(1));
@@ -295,7 +284,7 @@
 }
 
 void BufferLayer::setTransformHint(uint32_t orientation) const {
-    mSurfaceFlingerConsumer->setTransformHint(orientation);
+    mConsumer->setTransformHint(orientation);
 }
 
 bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
@@ -323,10 +312,10 @@
     }
 
     // Update mFrameTracker.
-    nsecs_t desiredPresentTime = mSurfaceFlingerConsumer->getTimestamp();
+    nsecs_t desiredPresentTime = mConsumer->getTimestamp();
     mFrameTracker.setDesiredPresentTime(desiredPresentTime);
 
-    std::shared_ptr<FenceTime> frameReadyFence = mSurfaceFlingerConsumer->getCurrentFenceTime();
+    std::shared_ptr<FenceTime> frameReadyFence = mConsumer->getCurrentFenceTime();
     if (frameReadyFence->isValid()) {
         mFrameTracker.setFrameReadyFence(std::move(frameReadyFence));
     } else {
@@ -351,7 +340,7 @@
 
 std::vector<OccupancyTracker::Segment> BufferLayer::getOccupancyHistory(bool forceFlush) {
     std::vector<OccupancyTracker::Segment> history;
-    status_t result = mSurfaceFlingerConsumer->getOccupancyHistory(forceFlush, &history);
+    status_t result = mConsumer->getOccupancyHistory(forceFlush, &history);
     if (result != NO_ERROR) {
         ALOGW("[%s] Failed to obtain occupancy history (%d)", mName.string(), result);
         return {};
@@ -360,16 +349,16 @@
 }
 
 bool BufferLayer::getTransformToDisplayInverse() const {
-    return mSurfaceFlingerConsumer->getTransformToDisplayInverse();
+    return mConsumer->getTransformToDisplayInverse();
 }
 
 void BufferLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
-    if (!mSurfaceFlingerConsumer->releasePendingBuffer()) {
+    if (!mConsumer->releasePendingBuffer()) {
         return;
     }
 
     auto releaseFenceTime =
-            std::make_shared<FenceTime>(mSurfaceFlingerConsumer->getPrevFinalReleaseFence());
+            std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
     mReleaseTimeline.updateSignalTimes();
     mReleaseTimeline.push(releaseFenceTime);
 
@@ -385,10 +374,10 @@
 
     if (android_atomic_acquire_cas(true, false, &mSidebandStreamChanged) == 0) {
         // mSidebandStreamChanged was true
-        mSidebandStream = mSurfaceFlingerConsumer->getSidebandStream();
+        mSidebandStream = mConsumer->getSidebandStream();
         // replicated in LayerBE until FE/BE is ready to be synchronized
-        getBE().mSidebandStream = mSidebandStream;
-        if (getBE().mSidebandStream != NULL) {
+        getBE().compositionInfo.hwc.sidebandStream = mSidebandStream;
+        if (getBE().compositionInfo.hwc.sidebandStream != NULL) {
             setTransactionFlags(eTransactionNeeded);
             mFlinger->setTransactionFlags(eTraversalNeeded);
         }
@@ -422,7 +411,7 @@
     // Capture the old state of the layer for comparisons later
     const State& s(getDrawingState());
     const bool oldOpacity = isOpaque(s);
-    sp<GraphicBuffer> oldBuffer = getBE().mBuffer;
+    sp<GraphicBuffer> oldBuffer = getBE().compositionInfo.mBuffer;
 
     if (!allTransactionsSignaled()) {
         mFlinger->signalLayerUpdate();
@@ -438,7 +427,7 @@
                     getProducerStickyTransform() != 0, mName.string(),
                     mOverrideScalingMode, mFreezeGeometryUpdates);
     status_t updateResult =
-            mSurfaceFlingerConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync,
+            mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync,
                                                     &mAutoRefresh, &queuedBuffer,
                                                     mLastFrameNumberReceived);
     if (updateResult == BufferQueue::PRESENT_LATER) {
@@ -446,7 +435,7 @@
         // layer update so we check again at the next opportunity.
         mFlinger->signalLayerUpdate();
         return outDirtyRegion;
-    } else if (updateResult == SurfaceFlingerConsumer::BUFFER_REJECTED) {
+    } else if (updateResult == BufferLayerConsumer::BUFFER_REJECTED) {
         // If the buffer has been rejected, remove it from the shadow queue
         // and return early
         if (queuedBuffer) {
@@ -477,7 +466,7 @@
 
     if (queuedBuffer) {
         // Autolock scope
-        auto currentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+        auto currentFrameNumber = mConsumer->getFrameNumber();
 
         Mutex::Autolock lock(mQueueItemLock);
 
@@ -499,18 +488,18 @@
     }
 
     // update the active buffer
-    getBE().mBuffer =
-            mSurfaceFlingerConsumer->getCurrentBuffer(&getBE().mBufferSlot);
+    getBE().compositionInfo.mBuffer =
+            mConsumer->getCurrentBuffer(&getBE().compositionInfo.mBufferSlot);
     // replicated in LayerBE until FE/BE is ready to be synchronized
-    mActiveBuffer = getBE().mBuffer;
-    if (getBE().mBuffer == NULL) {
+    mActiveBuffer = getBE().compositionInfo.mBuffer;
+    if (getBE().compositionInfo.mBuffer == NULL) {
         // this can only happen if the very first buffer was rejected.
         return outDirtyRegion;
     }
 
     mBufferLatched = true;
     mPreviousFrameNumber = mCurrentFrameNumber;
-    mCurrentFrameNumber = mSurfaceFlingerConsumer->getFrameNumber();
+    mCurrentFrameNumber = mConsumer->getFrameNumber();
 
     {
         Mutex::Autolock lock(mFrameEventHistoryMutex);
@@ -525,11 +514,11 @@
         recomputeVisibleRegions = true;
     }
 
-    setDataSpace(mSurfaceFlingerConsumer->getCurrentDataSpace());
+    setDataSpace(mConsumer->getCurrentDataSpace());
 
-    Rect crop(mSurfaceFlingerConsumer->getCurrentCrop());
-    const uint32_t transform(mSurfaceFlingerConsumer->getCurrentTransform());
-    const uint32_t scalingMode(mSurfaceFlingerConsumer->getCurrentScalingMode());
+    Rect crop(mConsumer->getCurrentCrop());
+    const uint32_t transform(mConsumer->getCurrentTransform());
+    const uint32_t scalingMode(mConsumer->getCurrentScalingMode());
     if ((crop != mCurrentCrop) ||
         (transform != mCurrentTransform) ||
         (scalingMode != mCurrentScalingMode)) {
@@ -540,15 +529,15 @@
     }
 
     if (oldBuffer != NULL) {
-        uint32_t bufWidth = getBE().mBuffer->getWidth();
-        uint32_t bufHeight = getBE().mBuffer->getHeight();
+        uint32_t bufWidth = getBE().compositionInfo.mBuffer->getWidth();
+        uint32_t bufHeight = getBE().compositionInfo.mBuffer->getHeight();
         if (bufWidth != uint32_t(oldBuffer->width) ||
             bufHeight != uint32_t(oldBuffer->height)) {
             recomputeVisibleRegions = true;
         }
     }
 
-    mCurrentOpacity = getOpacityForFormat(getBE().mBuffer->format);
+    mCurrentOpacity = getOpacityForFormat(getBE().compositionInfo.mBuffer->format);
     if (oldOpacity != isOpaque(s)) {
         recomputeVisibleRegions = true;
     }
@@ -584,7 +573,7 @@
 }
 
 void BufferLayer::setDefaultBufferSize(uint32_t w, uint32_t h) {
-    mSurfaceFlingerConsumer->setDefaultBufferSize(w, h);
+    mConsumer->setDefaultBufferSize(w, h);
 }
 
 void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
@@ -611,13 +600,13 @@
     }
 
     // Sideband layers
-    if (getBE().mSidebandStream.get()) {
+    if (getBE().compositionInfo.hwc.sidebandStream.get()) {
         setCompositionType(hwcId, HWC2::Composition::Sideband);
         ALOGV("[%s] Requesting Sideband composition", mName.string());
-        error = hwcLayer->setSidebandStream(getBE().mSidebandStream->handle());
+        error = hwcLayer->setSidebandStream(getBE().compositionInfo.hwc.sidebandStream->handle());
         if (error != HWC2::Error::None) {
             ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(),
-                  getBE().mSidebandStream->handle(), to_string(error).c_str(),
+                  getBE().compositionInfo.hwc.sidebandStream->handle(), to_string(error).c_str(),
                   static_cast<int32_t>(error));
         }
         return;
@@ -641,14 +630,14 @@
 
     uint32_t hwcSlot = 0;
     sp<GraphicBuffer> hwcBuffer;
-    hwcInfo.bufferCache.getHwcBuffer(getBE().mBufferSlot,
-                                     getBE().mBuffer, &hwcSlot, &hwcBuffer);
+    hwcInfo.bufferCache.getHwcBuffer(getBE().compositionInfo.mBufferSlot,
+                                     getBE().compositionInfo.mBuffer, &hwcSlot, &hwcBuffer);
 
-    auto acquireFence = mSurfaceFlingerConsumer->getCurrentFence();
+    auto acquireFence = mConsumer->getCurrentFence();
     error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
-              getBE().mBuffer->handle, to_string(error).c_str(),
+              getBE().compositionInfo.mBuffer->handle, to_string(error).c_str(),
               static_cast<int32_t>(error));
     }
 }
@@ -656,7 +645,7 @@
 bool BufferLayer::isOpaque(const Layer::State& s) const {
     // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
     // layer's opaque flag.
-    if ((getBE().mSidebandStream == nullptr) && (getBE().mBuffer == nullptr)) {
+    if ((getBE().compositionInfo.hwc.sidebandStream == nullptr) && (getBE().compositionInfo.mBuffer == nullptr)) {
         return false;
     }
 
@@ -671,10 +660,11 @@
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer, true);
     mProducer = new MonitoredProducer(producer, mFlinger, this);
-    mSurfaceFlingerConsumer = new SurfaceFlingerConsumer(consumer, mTextureName, this);
-    mSurfaceFlingerConsumer->setConsumerUsageBits(getEffectiveUsage(0));
-    mSurfaceFlingerConsumer->setContentsChangedListener(this);
-    mSurfaceFlingerConsumer->setName(mName);
+    mConsumer = new BufferLayerConsumer(consumer,
+            mFlinger->getRenderEngine(), mTextureName, this);
+    mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
+    mConsumer->setContentsChangedListener(this);
+    mConsumer->setName(mName);
 
     if (mFlinger->isLayerTripleBufferingDisabled()) {
         mProducer->setMaxDequeuedBufferCount(2);
@@ -798,16 +788,17 @@
      * minimal value)? Or, we could make GL behave like HWC -- but this feel
      * like more of a hack.
      */
-    Rect win(computeBounds());
+    const Rect bounds{computeBounds()}; // Rounds from FloatRect
 
     Transform t = getTransform();
+    Rect win = bounds;
     if (!s.finalCrop.isEmpty()) {
         win = t.transform(win);
         if (!win.intersect(s.finalCrop, &win)) {
             win.clear();
         }
         win = t.inverse().transform(win);
-        if (!win.intersect(computeBounds(), &win)) {
+        if (!win.intersect(bounds, &win)) {
             win.clear();
         }
     }
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index 1127952..6b02f8c 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -16,6 +16,7 @@
 
 #pragma once
 
+#include "BufferLayerConsumer.h"
 #include "Client.h"
 #include "Layer.h"
 #include "DisplayHardware/HWComposer.h"
@@ -26,7 +27,6 @@
 #include "RenderEngine/Mesh.h"
 #include "RenderEngine/Texture.h"
 #include "SurfaceFlinger.h"
-#include "SurfaceFlingerConsumer.h"
 #include "Transform.h"
 
 #include <gui/ISurfaceComposerClient.h>
@@ -48,13 +48,13 @@
 namespace android {
 
 /*
- * A new BufferQueue and a new SurfaceFlingerConsumer are created when the
+ * A new BufferQueue and a new BufferLayerConsumer are created when the
  * BufferLayer is first referenced.
  *
  * This also implements onFrameAvailable(), which notifies SurfaceFlinger
  * that new data has arrived.
  */
-class BufferLayer : public Layer, public SurfaceFlingerConsumer::ContentsChangedListener {
+class BufferLayer : public Layer, public BufferLayerConsumer::ContentsChangedListener {
 public:
     BufferLayer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
                 uint32_t h, uint32_t flags);
@@ -137,7 +137,7 @@
     void onFirstRef() override;
 
     // Interface implementation for
-    // SurfaceFlingerConsumer::ContentsChangedListener
+    // BufferLayerConsumer::ContentsChangedListener
     void onFrameAvailable(const BufferItem& item) override;
     void onFrameReplaced(const BufferItem& item) override;
     void onSidebandStreamChanged() override;
@@ -170,7 +170,7 @@
     sp<IGraphicBufferProducer> getProducer() const;
 
 private:
-    sp<SurfaceFlingerConsumer> mSurfaceFlingerConsumer;
+    sp<BufferLayerConsumer> mConsumer;
 
     // Check all of the local sync points to ensure that all transactions
     // which need to have been applied prior to the frame which is about to
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
new file mode 100644
index 0000000..976dde2
--- /dev/null
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -0,0 +1,626 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "BufferLayerConsumer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+//#define LOG_NDEBUG 0
+
+#include "BufferLayerConsumer.h"
+
+#include "DispSync.h"
+#include "Layer.h"
+#include "RenderEngine/RenderEngine.h"
+
+#include <inttypes.h>
+
+#include <cutils/compiler.h>
+
+#include <hardware/hardware.h>
+
+#include <math/mat4.h>
+
+#include <gui/BufferItem.h>
+#include <gui/GLConsumer.h>
+#include <gui/ISurfaceComposer.h>
+#include <gui/SurfaceComposerClient.h>
+
+#include <private/gui/ComposerService.h>
+#include <private/gui/SyncFeatures.h>
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+// Macros for including the BufferLayerConsumer name in log messages
+#define BLC_LOGV(x, ...) ALOGV("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define BLC_LOGD(x, ...) ALOGD("[%s] " x, mName.string(), ##__VA_ARGS__)
+//#define BLC_LOGI(x, ...) ALOGI("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define BLC_LOGW(x, ...) ALOGW("[%s] " x, mName.string(), ##__VA_ARGS__)
+#define BLC_LOGE(x, ...) ALOGE("[%s] " x, mName.string(), ##__VA_ARGS__)
+
+static const mat4 mtxIdentity;
+
+BufferLayerConsumer::BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, RenderEngine& engine,
+                                         uint32_t tex, Layer* layer)
+      : ConsumerBase(bq, false),
+        mCurrentCrop(Rect::EMPTY_RECT),
+        mCurrentTransform(0),
+        mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+        mCurrentFence(Fence::NO_FENCE),
+        mCurrentTimestamp(0),
+        mCurrentDataSpace(HAL_DATASPACE_UNKNOWN),
+        mCurrentFrameNumber(0),
+        mCurrentTransformToDisplayInverse(false),
+        mCurrentSurfaceDamage(),
+        mDefaultWidth(1),
+        mDefaultHeight(1),
+        mFilteringEnabled(true),
+        mRE(engine),
+        mTexName(tex),
+        mLayer(layer),
+        mCurrentTexture(BufferQueue::INVALID_BUFFER_SLOT) {
+    BLC_LOGV("BufferLayerConsumer");
+
+    memcpy(mCurrentTransformMatrix, mtxIdentity.asArray(), sizeof(mCurrentTransformMatrix));
+
+    mConsumer->setConsumerUsageBits(DEFAULT_USAGE_FLAGS);
+}
+
+status_t BufferLayerConsumer::setDefaultBufferSize(uint32_t w, uint32_t h) {
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        BLC_LOGE("setDefaultBufferSize: BufferLayerConsumer is abandoned!");
+        return NO_INIT;
+    }
+    mDefaultWidth = w;
+    mDefaultHeight = h;
+    return mConsumer->setDefaultBufferSize(w, h);
+}
+
+void BufferLayerConsumer::setContentsChangedListener(const wp<ContentsChangedListener>& listener) {
+    setFrameAvailableListener(listener);
+    Mutex::Autolock lock(mMutex);
+    mContentsChangedListener = listener;
+}
+
+// We need to determine the time when a buffer acquired now will be
+// displayed.  This can be calculated:
+//   time when previous buffer's actual-present fence was signaled
+//    + current display refresh rate * HWC latency
+//    + a little extra padding
+//
+// Buffer producers are expected to set their desired presentation time
+// based on choreographer time stamps, which (coming from vsync events)
+// will be slightly later then the actual-present timing.  If we get a
+// desired-present time that is unintentionally a hair after the next
+// vsync, we'll hold the frame when we really want to display it.  We
+// need to take the offset between actual-present and reported-vsync
+// into account.
+//
+// If the system is configured without a DispSync phase offset for the app,
+// we also want to throw in a bit of padding to avoid edge cases where we
+// just barely miss.  We want to do it here, not in every app.  A major
+// source of trouble is the app's use of the display's ideal refresh time
+// (via Display.getRefreshRate()), which could be off of the actual refresh
+// by a few percent, with the error multiplied by the number of frames
+// between now and when the buffer should be displayed.
+//
+// If the refresh reported to the app has a phase offset, we shouldn't need
+// to tweak anything here.
+nsecs_t BufferLayerConsumer::computeExpectedPresent(const DispSync& dispSync) {
+    // The HWC doesn't currently have a way to report additional latency.
+    // Assume that whatever we submit now will appear right after the flip.
+    // For a smart panel this might be 1.  This is expressed in frames,
+    // rather than time, because we expect to have a constant frame delay
+    // regardless of the refresh rate.
+    const uint32_t hwcLatency = 0;
+
+    // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
+    const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency);
+
+    // The DispSync time is already adjusted for the difference between
+    // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so
+    // we don't need to factor that in here.  Pad a little to avoid
+    // weird effects if apps might be requesting times right on the edge.
+    nsecs_t extraPadding = 0;
+    if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) {
+        extraPadding = 1000000; // 1ms (6% of 60Hz)
+    }
+
+    return nextRefresh + extraPadding;
+}
+
+status_t BufferLayerConsumer::updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync,
+                                             bool* autoRefresh, bool* queuedBuffer,
+                                             uint64_t maxFrameNumber) {
+    ATRACE_CALL();
+    BLC_LOGV("updateTexImage");
+    Mutex::Autolock lock(mMutex);
+
+    if (mAbandoned) {
+        BLC_LOGE("updateTexImage: BufferLayerConsumer is abandoned!");
+        return NO_INIT;
+    }
+
+    // Make sure RenderEngine is current
+    if (!mRE.isCurrent()) {
+        BLC_LOGE("updateTexImage: RenderEngine is not current");
+        return INVALID_OPERATION;
+    }
+
+    BufferItem item;
+
+    // Acquire the next buffer.
+    // In asynchronous mode the list is guaranteed to be one buffer
+    // deep, while in synchronous mode we use the oldest buffer.
+    status_t err = acquireBufferLocked(&item, computeExpectedPresent(dispSync), maxFrameNumber);
+    if (err != NO_ERROR) {
+        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
+            err = NO_ERROR;
+        } else if (err == BufferQueue::PRESENT_LATER) {
+            // return the error, without logging
+        } else {
+            BLC_LOGE("updateTexImage: acquire failed: %s (%d)", strerror(-err), err);
+        }
+        return err;
+    }
+
+    if (autoRefresh) {
+        *autoRefresh = item.mAutoRefresh;
+    }
+
+    if (queuedBuffer) {
+        *queuedBuffer = item.mQueuedBuffer;
+    }
+
+    // We call the rejecter here, in case the caller has a reason to
+    // not accept this buffer.  This is used by SurfaceFlinger to
+    // reject buffers which have the wrong size
+    int slot = item.mSlot;
+    if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) {
+        releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
+        return BUFFER_REJECTED;
+    }
+
+    // Release the previous buffer.
+    err = updateAndReleaseLocked(item, &mPendingRelease);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    if (!SyncFeatures::getInstance().useNativeFenceSync()) {
+        // Bind the new buffer to the GL texture.
+        //
+        // Older devices require the "implicit" synchronization provided
+        // by glEGLImageTargetTexture2DOES, which this method calls.  Newer
+        // devices will either call this in Layer::onDraw, or (if it's not
+        // a GL-composited layer) not at all.
+        err = bindTextureImageLocked();
+    }
+
+    return err;
+}
+
+status_t BufferLayerConsumer::bindTextureImage() {
+    Mutex::Autolock lock(mMutex);
+    return bindTextureImageLocked();
+}
+
+void BufferLayerConsumer::setReleaseFence(const sp<Fence>& fence) {
+    if (!fence->isValid()) {
+        return;
+    }
+
+    auto slot = mPendingRelease.isPending ? mPendingRelease.currentTexture : mCurrentTexture;
+    if (slot == BufferQueue::INVALID_BUFFER_SLOT) {
+        return;
+    }
+
+    auto buffer = mPendingRelease.isPending ? mPendingRelease.graphicBuffer
+                                            : mCurrentTextureImage->graphicBuffer();
+    auto err = addReleaseFence(slot, buffer, fence);
+    if (err != OK) {
+        BLC_LOGE("setReleaseFence: failed to add the fence: %s (%d)", strerror(-err), err);
+    }
+}
+
+bool BufferLayerConsumer::releasePendingBuffer() {
+    if (!mPendingRelease.isPending) {
+        BLC_LOGV("Pending buffer already released");
+        return false;
+    }
+    BLC_LOGV("Releasing pending buffer");
+    Mutex::Autolock lock(mMutex);
+    status_t result =
+            releaseBufferLocked(mPendingRelease.currentTexture, mPendingRelease.graphicBuffer);
+    if (result < NO_ERROR) {
+        BLC_LOGE("releasePendingBuffer failed: %s (%d)", strerror(-result), result);
+    }
+    mPendingRelease = PendingRelease();
+    return true;
+}
+
+sp<Fence> BufferLayerConsumer::getPrevFinalReleaseFence() const {
+    Mutex::Autolock lock(mMutex);
+    return ConsumerBase::mPrevFinalReleaseFence;
+}
+
+status_t BufferLayerConsumer::acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
+                                                  uint64_t maxFrameNumber) {
+    status_t err = ConsumerBase::acquireBufferLocked(item, presentWhen, maxFrameNumber);
+    if (err != NO_ERROR) {
+        return err;
+    }
+
+    // If item->mGraphicBuffer is not null, this buffer has not been acquired
+    // before, so any prior EglImage created is using a stale buffer. This
+    // replaces any old EglImage with a new one (using the new buffer).
+    if (item->mGraphicBuffer != NULL) {
+        mImages[item->mSlot] = new Image(item->mGraphicBuffer, mRE);
+    }
+
+    return NO_ERROR;
+}
+
+bool BufferLayerConsumer::canUseImageCrop(const Rect& crop) const {
+    // If the crop rect is not at the origin, we can't set the crop on the
+    // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
+    // extension.  In the future we can add a layered extension that
+    // removes this restriction if there is hardware that can support it.
+    return mRE.supportsImageCrop() && crop.left == 0 && crop.top == 0;
+}
+
+status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
+                                                     PendingRelease* pendingRelease) {
+    status_t err = NO_ERROR;
+
+    int slot = item.mSlot;
+
+    // Do whatever sync ops we need to do before releasing the old slot.
+    if (slot != mCurrentTexture) {
+        err = syncForReleaseLocked();
+        if (err != NO_ERROR) {
+            // Release the buffer we just acquired.  It's not safe to
+            // release the old buffer, so instead we just drop the new frame.
+            // As we are still under lock since acquireBuffer, it is safe to
+            // release by slot.
+            releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer);
+            return err;
+        }
+    }
+
+    BLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)", mCurrentTexture,
+             mCurrentTextureImage != NULL ? mCurrentTextureImage->graphicBufferHandle() : 0, slot,
+             mSlots[slot].mGraphicBuffer->handle);
+
+    // Hang onto the pointer so that it isn't freed in the call to
+    // releaseBufferLocked() if we're in shared buffer mode and both buffers are
+    // the same.
+    sp<Image> nextTextureImage = mImages[slot];
+
+    // release old buffer
+    if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+        if (pendingRelease == nullptr) {
+            status_t status =
+                    releaseBufferLocked(mCurrentTexture, mCurrentTextureImage->graphicBuffer());
+            if (status < NO_ERROR) {
+                BLC_LOGE("updateAndRelease: failed to release buffer: %s (%d)", strerror(-status),
+                         status);
+                err = status;
+                // keep going, with error raised [?]
+            }
+        } else {
+            pendingRelease->currentTexture = mCurrentTexture;
+            pendingRelease->graphicBuffer = mCurrentTextureImage->graphicBuffer();
+            pendingRelease->isPending = true;
+        }
+    }
+
+    // Update the BufferLayerConsumer state.
+    mCurrentTexture = slot;
+    mCurrentTextureImage = nextTextureImage;
+    mCurrentCrop = item.mCrop;
+    mCurrentTransform = item.mTransform;
+    mCurrentScalingMode = item.mScalingMode;
+    mCurrentTimestamp = item.mTimestamp;
+    mCurrentDataSpace = item.mDataSpace;
+    mCurrentFence = item.mFence;
+    mCurrentFenceTime = item.mFenceTime;
+    mCurrentFrameNumber = item.mFrameNumber;
+    mCurrentTransformToDisplayInverse = item.mTransformToDisplayInverse;
+    mCurrentSurfaceDamage = item.mSurfaceDamage;
+
+    computeCurrentTransformMatrixLocked();
+
+    return err;
+}
+
+status_t BufferLayerConsumer::bindTextureImageLocked() {
+    mRE.checkErrors();
+
+    if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT && mCurrentTextureImage == NULL) {
+        BLC_LOGE("bindTextureImage: no currently-bound texture");
+        mRE.bindExternalTextureImage(mTexName, RE::Image(mRE));
+        return NO_INIT;
+    }
+
+    const Rect& imageCrop = canUseImageCrop(mCurrentCrop) ? mCurrentCrop : Rect::EMPTY_RECT;
+    status_t err = mCurrentTextureImage->createIfNeeded(imageCrop);
+    if (err != NO_ERROR) {
+        BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture);
+        mRE.bindExternalTextureImage(mTexName, RE::Image(mRE));
+        return UNKNOWN_ERROR;
+    }
+
+    mRE.bindExternalTextureImage(mTexName, mCurrentTextureImage->image());
+
+    // Wait for the new buffer to be ready.
+    return doFenceWaitLocked();
+}
+
+status_t BufferLayerConsumer::syncForReleaseLocked() {
+    BLC_LOGV("syncForReleaseLocked");
+
+    if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
+        if (SyncFeatures::getInstance().useNativeFenceSync()) {
+            base::unique_fd fenceFd = mRE.flush();
+            if (fenceFd == -1) {
+                BLC_LOGE("syncForReleaseLocked: failed to flush RenderEngine");
+                return UNKNOWN_ERROR;
+            }
+            sp<Fence> fence(new Fence(std::move(fenceFd)));
+            status_t err = addReleaseFenceLocked(mCurrentTexture,
+                                                 mCurrentTextureImage->graphicBuffer(), fence);
+            if (err != OK) {
+                BLC_LOGE("syncForReleaseLocked: error adding release fence: "
+                         "%s (%d)",
+                         strerror(-err), err);
+                return err;
+            }
+        }
+    }
+
+    return OK;
+}
+
+void BufferLayerConsumer::getTransformMatrix(float mtx[16]) {
+    Mutex::Autolock lock(mMutex);
+    memcpy(mtx, mCurrentTransformMatrix, sizeof(mCurrentTransformMatrix));
+}
+
+void BufferLayerConsumer::setFilteringEnabled(bool enabled) {
+    Mutex::Autolock lock(mMutex);
+    if (mAbandoned) {
+        BLC_LOGE("setFilteringEnabled: BufferLayerConsumer is abandoned!");
+        return;
+    }
+    bool needsRecompute = mFilteringEnabled != enabled;
+    mFilteringEnabled = enabled;
+
+    if (needsRecompute && mCurrentTextureImage == NULL) {
+        BLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL");
+    }
+
+    if (needsRecompute && mCurrentTextureImage != NULL) {
+        computeCurrentTransformMatrixLocked();
+    }
+}
+
+void BufferLayerConsumer::computeCurrentTransformMatrixLocked() {
+    BLC_LOGV("computeCurrentTransformMatrixLocked");
+    sp<GraphicBuffer> buf =
+            (mCurrentTextureImage == nullptr) ? nullptr : mCurrentTextureImage->graphicBuffer();
+    if (buf == nullptr) {
+        BLC_LOGD("computeCurrentTransformMatrixLocked: "
+                 "mCurrentTextureImage is NULL");
+    }
+    const Rect& cropRect = canUseImageCrop(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop;
+    GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf, cropRect, mCurrentTransform,
+                                       mFilteringEnabled);
+}
+
+nsecs_t BufferLayerConsumer::getTimestamp() {
+    BLC_LOGV("getTimestamp");
+    Mutex::Autolock lock(mMutex);
+    return mCurrentTimestamp;
+}
+
+android_dataspace BufferLayerConsumer::getCurrentDataSpace() {
+    BLC_LOGV("getCurrentDataSpace");
+    Mutex::Autolock lock(mMutex);
+    return mCurrentDataSpace;
+}
+
+uint64_t BufferLayerConsumer::getFrameNumber() {
+    BLC_LOGV("getFrameNumber");
+    Mutex::Autolock lock(mMutex);
+    return mCurrentFrameNumber;
+}
+
+bool BufferLayerConsumer::getTransformToDisplayInverse() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentTransformToDisplayInverse;
+}
+
+const Region& BufferLayerConsumer::getSurfaceDamage() const {
+    return mCurrentSurfaceDamage;
+}
+
+sp<GraphicBuffer> BufferLayerConsumer::getCurrentBuffer(int* outSlot) const {
+    Mutex::Autolock lock(mMutex);
+
+    if (outSlot != nullptr) {
+        *outSlot = mCurrentTexture;
+    }
+
+    return (mCurrentTextureImage == nullptr) ? NULL : mCurrentTextureImage->graphicBuffer();
+}
+
+Rect BufferLayerConsumer::getCurrentCrop() const {
+    Mutex::Autolock lock(mMutex);
+    return (mCurrentScalingMode == NATIVE_WINDOW_SCALING_MODE_SCALE_CROP)
+            ? GLConsumer::scaleDownCrop(mCurrentCrop, mDefaultWidth, mDefaultHeight)
+            : mCurrentCrop;
+}
+
+uint32_t BufferLayerConsumer::getCurrentTransform() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentTransform;
+}
+
+uint32_t BufferLayerConsumer::getCurrentScalingMode() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentScalingMode;
+}
+
+sp<Fence> BufferLayerConsumer::getCurrentFence() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentFence;
+}
+
+std::shared_ptr<FenceTime> BufferLayerConsumer::getCurrentFenceTime() const {
+    Mutex::Autolock lock(mMutex);
+    return mCurrentFenceTime;
+}
+
+status_t BufferLayerConsumer::doFenceWaitLocked() const {
+    if (!mRE.isCurrent()) {
+        BLC_LOGE("doFenceWait: RenderEngine is not current");
+        return INVALID_OPERATION;
+    }
+
+    if (mCurrentFence->isValid()) {
+        if (SyncFeatures::getInstance().useWaitSync()) {
+            base::unique_fd fenceFd(mCurrentFence->dup());
+            if (fenceFd == -1) {
+                BLC_LOGE("doFenceWait: error dup'ing fence fd: %d", errno);
+                return -errno;
+            }
+            if (!mRE.waitFence(std::move(fenceFd))) {
+                BLC_LOGE("doFenceWait: failed to wait on fence fd");
+                return UNKNOWN_ERROR;
+            }
+        } else {
+            status_t err = mCurrentFence->waitForever("BufferLayerConsumer::doFenceWaitLocked");
+            if (err != NO_ERROR) {
+                BLC_LOGE("doFenceWait: error waiting for fence: %d", err);
+                return err;
+            }
+        }
+    }
+
+    return NO_ERROR;
+}
+
+void BufferLayerConsumer::freeBufferLocked(int slotIndex) {
+    BLC_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
+    if (slotIndex == mCurrentTexture) {
+        mCurrentTexture = BufferQueue::INVALID_BUFFER_SLOT;
+    }
+    mImages[slotIndex].clear();
+    ConsumerBase::freeBufferLocked(slotIndex);
+}
+
+void BufferLayerConsumer::onDisconnect() {
+    sp<Layer> l = mLayer.promote();
+    if (l.get()) {
+        l->onDisconnect();
+    }
+}
+
+void BufferLayerConsumer::onSidebandStreamChanged() {
+    FrameAvailableListener* unsafeFrameAvailableListener = nullptr;
+    {
+        Mutex::Autolock lock(mFrameAvailableMutex);
+        unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get();
+    }
+    sp<ContentsChangedListener> listener;
+    { // scope for the lock
+        Mutex::Autolock lock(mMutex);
+        ALOG_ASSERT(unsafeFrameAvailableListener == mContentsChangedListener.unsafe_get());
+        listener = mContentsChangedListener.promote();
+    }
+
+    if (listener != NULL) {
+        listener->onSidebandStreamChanged();
+    }
+}
+
+void BufferLayerConsumer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
+                                                   FrameEventHistoryDelta* outDelta) {
+    sp<Layer> l = mLayer.promote();
+    if (l.get()) {
+        l->addAndGetFrameTimestamps(newTimestamps, outDelta);
+    }
+}
+
+void BufferLayerConsumer::abandonLocked() {
+    BLC_LOGV("abandonLocked");
+    mCurrentTextureImage.clear();
+    ConsumerBase::abandonLocked();
+}
+
+status_t BufferLayerConsumer::setConsumerUsageBits(uint64_t usage) {
+    return ConsumerBase::setConsumerUsageBits(usage | DEFAULT_USAGE_FLAGS);
+}
+
+void BufferLayerConsumer::dumpLocked(String8& result, const char* prefix) const {
+    result.appendFormat("%smTexName=%d mCurrentTexture=%d\n"
+                        "%smCurrentCrop=[%d,%d,%d,%d] mCurrentTransform=%#x\n",
+                        prefix, mTexName, mCurrentTexture, prefix, mCurrentCrop.left,
+                        mCurrentCrop.top, mCurrentCrop.right, mCurrentCrop.bottom,
+                        mCurrentTransform);
+
+    ConsumerBase::dumpLocked(result, prefix);
+}
+
+BufferLayerConsumer::Image::Image(sp<GraphicBuffer> graphicBuffer, const RenderEngine& engine)
+      : mGraphicBuffer(graphicBuffer),
+        mImage{engine},
+        mCreated(false),
+        mCropWidth(0),
+        mCropHeight(0) {}
+
+status_t BufferLayerConsumer::Image::createIfNeeded(const Rect& imageCrop) {
+    const int32_t cropWidth = imageCrop.width();
+    const int32_t cropHeight = imageCrop.height();
+    if (mCreated && mCropWidth == cropWidth && mCropHeight == cropHeight) {
+        return OK;
+    }
+
+    mCreated = mImage.setNativeWindowBuffer(mGraphicBuffer->getNativeBuffer(),
+                                            mGraphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED,
+                                            cropWidth, cropHeight);
+    if (mCreated) {
+        mCropWidth = cropWidth;
+        mCropHeight = cropHeight;
+    } else {
+        mCropWidth = 0;
+        mCropHeight = 0;
+
+        const sp<GraphicBuffer>& buffer = mGraphicBuffer;
+        ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
+              buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
+              buffer->getPixelFormat());
+    }
+
+    return mCreated ? OK : UNKNOWN_ERROR;
+}
+
+}; // namespace android
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
new file mode 100644
index 0000000..9b18608
--- /dev/null
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_BUFFERLAYERCONSUMER_H
+#define ANDROID_BUFFERLAYERCONSUMER_H
+
+#include "RenderEngine/Image.h"
+
+#include <gui/BufferQueueDefs.h>
+#include <gui/ConsumerBase.h>
+
+#include <ui/FenceTime.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/Region.h>
+
+#include <utils/String8.h>
+#include <utils/Vector.h>
+#include <utils/threads.h>
+
+namespace android {
+// ----------------------------------------------------------------------------
+
+class DispSync;
+class Layer;
+class RenderEngine;
+class String8;
+
+/*
+ * BufferLayerConsumer consumes buffers of graphics data from a BufferQueue,
+ * and makes them available to RenderEngine as a texture.
+ *
+ * A typical usage pattern is to call updateTexImage() when a new frame is
+ * desired.  If a new frame is available, the frame is latched.  If not, the
+ * previous contents are retained.  The texture is attached and updated after
+ * bindTextureImage() is called.
+ *
+ * All calls to updateTexImage must be made with RenderEngine being current.
+ * The texture is attached to the TEXTURE_EXTERNAL texture target.
+ */
+class BufferLayerConsumer : public ConsumerBase {
+public:
+    static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8;
+
+    class BufferRejecter {
+        friend class BufferLayerConsumer;
+        virtual bool reject(const sp<GraphicBuffer>& buf, const BufferItem& item) = 0;
+
+    protected:
+        virtual ~BufferRejecter() {}
+    };
+
+    struct ContentsChangedListener : public FrameAvailableListener {
+        virtual void onSidebandStreamChanged() = 0;
+    };
+
+    // BufferLayerConsumer constructs a new BufferLayerConsumer object.  The
+    // tex parameter indicates the name of the RenderEngine texture to which
+    // images are to be streamed.
+    BufferLayerConsumer(const sp<IGraphicBufferConsumer>& bq, RenderEngine& engine, uint32_t tex,
+                        Layer* layer);
+
+    // Sets the contents changed listener. This should be used instead of
+    // ConsumerBase::setFrameAvailableListener().
+    void setContentsChangedListener(const wp<ContentsChangedListener>& listener);
+
+    nsecs_t computeExpectedPresent(const DispSync& dispSync);
+
+    // updateTexImage acquires the most recently queued buffer, and sets the
+    // image contents of the target texture to it.
+    //
+    // This call may only be made while RenderEngine is current.
+    //
+    // This calls doFenceWait to ensure proper synchronization unless native
+    // fence is supported.
+    //
+    // Unlike the GLConsumer version, this version takes a functor that may be
+    // used to reject the newly acquired buffer.  It also does not bind the
+    // RenderEngine texture until bindTextureImage is called.
+    status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync, bool* autoRefresh,
+                            bool* queuedBuffer, uint64_t maxFrameNumber);
+
+    // See BufferLayerConsumer::bindTextureImageLocked().
+    status_t bindTextureImage();
+
+    // setReleaseFence stores a fence that will signal when the current buffer
+    // is no longer being read. This fence will be returned to the producer
+    // when the current buffer is released by updateTexImage(). Multiple
+    // fences can be set for a given buffer; they will be merged into a single
+    // union fence.
+    void setReleaseFence(const sp<Fence>& fence);
+
+    bool releasePendingBuffer();
+
+    sp<Fence> getPrevFinalReleaseFence() const;
+
+    // See GLConsumer::getTransformMatrix.
+    void getTransformMatrix(float mtx[16]);
+
+    // getTimestamp retrieves the timestamp associated with the texture image
+    // set by the most recent call to updateTexImage.
+    //
+    // The timestamp is in nanoseconds, and is monotonically increasing. Its
+    // other semantics (zero point, etc) are source-dependent and should be
+    // documented by the source.
+    int64_t getTimestamp();
+
+    // getDataSpace retrieves the DataSpace associated with the texture image
+    // set by the most recent call to updateTexImage.
+    android_dataspace getCurrentDataSpace();
+
+    // getFrameNumber retrieves the frame number associated with the texture
+    // image set by the most recent call to updateTexImage.
+    //
+    // The frame number is an incrementing counter set to 0 at the creation of
+    // the BufferQueue associated with this consumer.
+    uint64_t getFrameNumber();
+
+    bool getTransformToDisplayInverse() const;
+
+    // must be called from SF main thread
+    const Region& getSurfaceDamage() const;
+
+    // See GLConsumer::setDefaultBufferSize.
+    status_t setDefaultBufferSize(uint32_t width, uint32_t height);
+
+    // setFilteringEnabled sets whether the transform matrix should be computed
+    // for use with bilinear filtering.
+    void setFilteringEnabled(bool enabled);
+
+    // getCurrentBuffer returns the buffer associated with the current image.
+    // When outSlot is not nullptr, the current buffer slot index is also
+    // returned.
+    sp<GraphicBuffer> getCurrentBuffer(int* outSlot = nullptr) const;
+
+    // getCurrentCrop returns the cropping rectangle of the current buffer.
+    Rect getCurrentCrop() const;
+
+    // getCurrentTransform returns the transform of the current buffer.
+    uint32_t getCurrentTransform() const;
+
+    // getCurrentScalingMode returns the scaling mode of the current buffer.
+    uint32_t getCurrentScalingMode() const;
+
+    // getCurrentFence returns the fence indicating when the current buffer is
+    // ready to be read from.
+    sp<Fence> getCurrentFence() const;
+
+    // getCurrentFence returns the FenceTime indicating when the current
+    // buffer is ready to be read from.
+    std::shared_ptr<FenceTime> getCurrentFenceTime() const;
+
+    // setConsumerUsageBits overrides the ConsumerBase method to OR
+    // DEFAULT_USAGE_FLAGS to usage.
+    status_t setConsumerUsageBits(uint64_t usage);
+
+protected:
+    // abandonLocked overrides the ConsumerBase method to clear
+    // mCurrentTextureImage in addition to the ConsumerBase behavior.
+    virtual void abandonLocked();
+
+    // dumpLocked overrides the ConsumerBase method to dump BufferLayerConsumer-
+    // specific info in addition to the ConsumerBase behavior.
+    virtual void dumpLocked(String8& result, const char* prefix) const;
+
+    // acquireBufferLocked overrides the ConsumerBase method to update the
+    // mImages array in addition to the ConsumerBase behavior.
+    virtual status_t acquireBufferLocked(BufferItem* item, nsecs_t presentWhen,
+                                         uint64_t maxFrameNumber = 0) override;
+
+    bool canUseImageCrop(const Rect& crop) const;
+
+    struct PendingRelease {
+        PendingRelease() : isPending(false), currentTexture(-1), graphicBuffer() {}
+
+        bool isPending;
+        int currentTexture;
+        sp<GraphicBuffer> graphicBuffer;
+    };
+
+    // This releases the buffer in the slot referenced by mCurrentTexture,
+    // then updates state to refer to the BufferItem, which must be a
+    // newly-acquired buffer. If pendingRelease is not null, the parameters
+    // which would have been passed to releaseBufferLocked upon the successful
+    // completion of the method will instead be returned to the caller, so that
+    // it may call releaseBufferLocked itself later.
+    status_t updateAndReleaseLocked(const BufferItem& item,
+                                    PendingRelease* pendingRelease = nullptr);
+
+    // Binds mTexName and the current buffer to TEXTURE_EXTERNAL target.  Uses
+    // mCurrentTexture if it's set, mCurrentTextureImage if not.  If the
+    // bind succeeds, this calls doFenceWait.
+    status_t bindTextureImageLocked();
+
+private:
+    // Image is a utility class for tracking and creating RE::Images. There
+    // is primarily just one image per slot, but there is also special cases:
+    //  - After freeBuffer, we must still keep the current image/buffer
+    // Reference counting RE::Images lets us handle all these cases easily while
+    // also only creating new RE::Images from buffers when required.
+    class Image : public LightRefBase<Image> {
+    public:
+        Image(sp<GraphicBuffer> graphicBuffer, const RenderEngine& engine);
+
+        Image(const Image& rhs) = delete;
+        Image& operator=(const Image& rhs) = delete;
+
+        // createIfNeeded creates an RE::Image if required (we haven't created
+        // one yet, or the crop-rect has changed).
+        status_t createIfNeeded(const Rect& imageCrop);
+
+        const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
+        const native_handle* graphicBufferHandle() {
+            return mGraphicBuffer == NULL ? NULL : mGraphicBuffer->handle;
+        }
+
+        const RE::Image& image() const { return mImage; }
+
+    private:
+        // Only allow instantiation using ref counting.
+        friend class LightRefBase<Image>;
+        virtual ~Image() = default;
+
+        // mGraphicBuffer is the buffer that was used to create this image.
+        sp<GraphicBuffer> mGraphicBuffer;
+
+        // mImage is the image created from mGraphicBuffer.
+        RE::Image mImage;
+        bool mCreated;
+        int32_t mCropWidth;
+        int32_t mCropHeight;
+    };
+
+    // freeBufferLocked frees up the given buffer slot. If the slot has been
+    // initialized this will release the reference to the GraphicBuffer in
+    // that slot and destroy the RE::Image in that slot.  Otherwise it has no
+    // effect.
+    //
+    // This method must be called with mMutex locked.
+    virtual void freeBufferLocked(int slotIndex);
+
+    // IConsumerListener interface
+    void onDisconnect() override;
+    void onSidebandStreamChanged() override;
+    void addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
+                                  FrameEventHistoryDelta* outDelta) override;
+
+    // computeCurrentTransformMatrixLocked computes the transform matrix for the
+    // current texture.  It uses mCurrentTransform and the current GraphicBuffer
+    // to compute this matrix and stores it in mCurrentTransformMatrix.
+    // mCurrentTextureImage must not be NULL.
+    void computeCurrentTransformMatrixLocked();
+
+    // doFenceWaitLocked inserts a wait command into the RenderEngine command
+    // stream to ensure that it is safe for future RenderEngine commands to
+    // access the current texture buffer.
+    status_t doFenceWaitLocked() const;
+
+    // syncForReleaseLocked performs the synchronization needed to release the
+    // current slot from RenderEngine.  If needed it will set the current
+    // slot's fence to guard against a producer accessing the buffer before
+    // the outstanding accesses have completed.
+    status_t syncForReleaseLocked();
+
+    // The default consumer usage flags that BufferLayerConsumer always sets on its
+    // BufferQueue instance; these will be OR:d with any additional flags passed
+    // from the BufferLayerConsumer user. In particular, BufferLayerConsumer will always
+    // consume buffers as hardware textures.
+    static const uint64_t DEFAULT_USAGE_FLAGS = GraphicBuffer::USAGE_HW_TEXTURE;
+
+    // mCurrentTextureImage is the Image/buffer of the current texture. It's
+    // possible that this buffer is not associated with any buffer slot, so we
+    // must track it separately in order to support the getCurrentBuffer method.
+    sp<Image> mCurrentTextureImage;
+
+    // mCurrentCrop is the crop rectangle that applies to the current texture.
+    // It gets set each time updateTexImage is called.
+    Rect mCurrentCrop;
+
+    // mCurrentTransform is the transform identifier for the current texture. It
+    // gets set each time updateTexImage is called.
+    uint32_t mCurrentTransform;
+
+    // mCurrentScalingMode is the scaling mode for the current texture. It gets
+    // set each time updateTexImage is called.
+    uint32_t mCurrentScalingMode;
+
+    // mCurrentFence is the fence received from BufferQueue in updateTexImage.
+    sp<Fence> mCurrentFence;
+
+    // The FenceTime wrapper around mCurrentFence.
+    std::shared_ptr<FenceTime> mCurrentFenceTime{FenceTime::NO_FENCE};
+
+    // mCurrentTransformMatrix is the transform matrix for the current texture.
+    // It gets computed by computeTransformMatrix each time updateTexImage is
+    // called.
+    float mCurrentTransformMatrix[16];
+
+    // mCurrentTimestamp is the timestamp for the current texture. It
+    // gets set each time updateTexImage is called.
+    int64_t mCurrentTimestamp;
+
+    // mCurrentDataSpace is the dataspace for the current texture. It
+    // gets set each time updateTexImage is called.
+    android_dataspace mCurrentDataSpace;
+
+    // mCurrentFrameNumber is the frame counter for the current texture.
+    // It gets set each time updateTexImage is called.
+    uint64_t mCurrentFrameNumber;
+
+    // Indicates this buffer must be transformed by the inverse transform of the screen
+    // it is displayed onto. This is applied after BufferLayerConsumer::mCurrentTransform.
+    // This must be set/read from SurfaceFlinger's main thread.
+    bool mCurrentTransformToDisplayInverse;
+
+    // The portion of this surface that has changed since the previous frame
+    Region mCurrentSurfaceDamage;
+
+    uint32_t mDefaultWidth, mDefaultHeight;
+
+    // mFilteringEnabled indicates whether the transform matrix is computed for
+    // use with bilinear filtering. It defaults to true and is changed by
+    // setFilteringEnabled().
+    bool mFilteringEnabled;
+
+    RenderEngine& mRE;
+
+    // mTexName is the name of the RenderEngine texture to which streamed
+    // images will be bound when bindTexImage is called. It is set at
+    // construction time.
+    const uint32_t mTexName;
+
+    // The layer for this BufferLayerConsumer
+    const wp<Layer> mLayer;
+
+    wp<ContentsChangedListener> mContentsChangedListener;
+
+    // mImages stores the buffers that have been allocated by the BufferQueue
+    // for each buffer slot.  It is initialized to null pointers, and gets
+    // filled in with the result of BufferQueue::acquire when the
+    // client dequeues a buffer from a
+    // slot that has not yet been used. The buffer allocated to a slot will also
+    // be replaced if the requested buffer usage or geometry differs from that
+    // of the buffer allocated to a slot.
+    sp<Image> mImages[BufferQueueDefs::NUM_BUFFER_SLOTS];
+
+    // mCurrentTexture is the buffer slot index of the buffer that is currently
+    // bound to the RenderEngine 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;
+
+    // A release that is pending on the receipt of a new release fence from
+    // presentDisplay
+    PendingRelease mPendingRelease;
+};
+
+// ----------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_BUFFERLAYERCONSUMER_H
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 60b85c5..c0f8f96 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -444,10 +444,16 @@
 
     HWC2::Error error = HWC2::Error::None;
 
-    // First try to skip validate altogether if the HWC supports it.
+    // First try to skip validate altogether when there is no client
+    // composition.  When there is client composition, since we haven't
+    // rendered to the client target yet, we should not attempt to skip
+    // validate.
+    //
+    // displayData.hasClientComposition hasn't been updated for this frame.
+    // The check below is incorrect.  We actually rely on HWC here to fall
+    // back to validate when there is any client layer.
     displayData.validateWasSkipped = false;
-    if (hasCapability(HWC2::Capability::SkipValidate) &&
-            !displayData.hasClientComposition) {
+    if (!displayData.hasClientComposition) {
         sp<android::Fence> outPresentFence;
         uint32_t state = UINT32_MAX;
         error = hwcDisplay->presentOrValidate(&numTypes, &numRequests, &outPresentFence , &state);
diff --git a/services/surfaceflinger/DisplayHardware/PowerHAL.cpp b/services/surfaceflinger/DisplayHardware/PowerHAL.cpp
deleted file mode 100644
index a6f076e..0000000
--- a/services/surfaceflinger/DisplayHardware/PowerHAL.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android/hardware/power/1.0/IPower.h>
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <android/log.h>
-#include <utils/Errors.h>
-
-#include <binder/IServiceManager.h>
-#include <powermanager/IPowerManager.h>
-#include <powermanager/PowerManager.h>
-
-#include "PowerHAL.h"
-
-using android::hardware::power::V1_0::PowerHint;
-namespace android {
-// ---------------------------------------------------------------------------
-
-status_t PowerHAL::vsyncHint(bool enabled) {
-    Mutex::Autolock _l(mlock);
-    if (mPowerManager == NULL) {
-        const String16 serviceName("power");
-        sp<IBinder> bs = defaultServiceManager()->checkService(serviceName);
-        if (bs == NULL) {
-            return NAME_NOT_FOUND;
-        }
-        mPowerManager = interface_cast<IPowerManager>(bs);
-    }
-    status_t status;
-    status = mPowerManager->powerHint(static_cast<int>(PowerHint::VSYNC),
-            enabled ? 1 : 0);
-    if(status == DEAD_OBJECT) {
-        mPowerManager = NULL;
-    }
-    return status;
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
diff --git a/services/surfaceflinger/DisplayHardware/PowerHAL.h b/services/surfaceflinger/DisplayHardware/PowerHAL.h
deleted file mode 100644
index e5f82a9..0000000
--- a/services/surfaceflinger/DisplayHardware/PowerHAL.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SF_POWER_HAL_H
-#define ANDROID_SF_POWER_HAL_H
-
-#include <stdint.h>
-#include <sys/types.h>
-#include <utils/Mutex.h>
-
-#include <powermanager/IPowerManager.h>
-#include <hardware/power.h>
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-class PowerHAL
-{
-public:
-    status_t vsyncHint(bool enabled);
-
-private:
-    sp<IPowerManager> mPowerManager;
-    Mutex mlock;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_SF_POWER_HAL_H
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index f647742..a1a0420 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -34,14 +34,6 @@
 // ---------------------------------------------------------------------------
 namespace android {
 // ---------------------------------------------------------------------------
-// time to wait between VSYNC requests before sending a VSYNC OFF power hint: 40msec.
-const long vsyncHintOffDelay = 40000000;
-
-static void vsyncOffCallback(union sigval val) {
-    EventThread *ev = (EventThread *)val.sival_ptr;
-    ev->sendVsyncHintOff();
-    return;
-}
 
 EventThread::EventThread(const sp<VSyncSource>& src, SurfaceFlinger& flinger, bool interceptVSyncs)
     : mVSyncSource(src),
@@ -49,7 +41,6 @@
       mUseSoftwareVSync(false),
       mVsyncEnabled(false),
       mDebugVsyncEnabled(false),
-      mVsyncHintSent(false),
       mInterceptVSyncs(interceptVSyncs) {
 
     for (int32_t i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
@@ -58,18 +49,6 @@
         mVSyncEvent[i].header.timestamp = 0;
         mVSyncEvent[i].vsync.count =  0;
     }
-    struct sigevent se;
-    se.sigev_notify = SIGEV_THREAD;
-    se.sigev_value.sival_ptr = this;
-    se.sigev_notify_function = vsyncOffCallback;
-    se.sigev_notify_attributes = NULL;
-    timer_create(CLOCK_MONOTONIC, &se, &mTimerId);
-}
-
-void EventThread::sendVsyncHintOff() {
-    Mutex::Autolock _l(mLock);
-    mPowerHAL.vsyncHint(false);
-    mVsyncHintSent = false;
 }
 
 void EventThread::setPhaseOffset(nsecs_t phaseOffset) {
@@ -77,19 +56,6 @@
     mVSyncSource->setPhaseOffset(phaseOffset);
 }
 
-void EventThread::sendVsyncHintOnLocked() {
-    struct itimerspec ts;
-    if(!mVsyncHintSent) {
-        mPowerHAL.vsyncHint(true);
-        mVsyncHintSent = true;
-    }
-    ts.it_value.tv_sec = 0;
-    ts.it_value.tv_nsec = vsyncHintOffDelay;
-    ts.it_interval.tv_sec = 0;
-    ts.it_interval.tv_nsec = 0;
-    timer_settime(mTimerId, 0, &ts, NULL);
-}
-
 void EventThread::onFirstRef() {
     run("EventThread", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
 }
@@ -357,7 +323,6 @@
         }
     }
     mDebugVsyncEnabled = true;
-    sendVsyncHintOnLocked();
 }
 
 void EventThread::disableVSyncLocked() {
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 6a59fbb..0823839 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -29,7 +29,6 @@
 #include <utils/SortedVector.h>
 
 #include "DisplayDevice.h"
-#include "DisplayHardware/PowerHAL.h"
 
 // ---------------------------------------------------------------------------
 namespace android {
@@ -99,7 +98,6 @@
             DisplayEventReceiver::Event* event);
 
     void dump(String8& result) const;
-    void sendVsyncHintOff();
 
     void setPhaseOffset(nsecs_t phaseOffset);
 
@@ -112,11 +110,9 @@
     void removeDisplayEventConnection(const wp<Connection>& connection);
     void enableVSyncLocked();
     void disableVSyncLocked();
-    void sendVsyncHintOnLocked();
 
     // constants
     sp<VSyncSource> mVSyncSource;
-    PowerHAL mPowerHAL;
     SurfaceFlinger& mFlinger;
 
     mutable Mutex mLock;
@@ -132,9 +128,7 @@
     // for debugging
     bool mDebugVsyncEnabled;
 
-    bool mVsyncHintSent;
     const bool mInterceptVSyncs;
-    timer_t mTimerId;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index ff5e6f6..cc675c4 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -39,7 +39,6 @@
 #include <ui/PixelFormat.h>
 
 #include <gui/BufferItem.h>
-#include <gui/BufferQueue.h>
 #include <gui/LayerDebugInfo.h>
 #include <gui/Surface.h>
 
@@ -63,9 +62,7 @@
 namespace android {
 
 LayerBE::LayerBE()
-      : mBufferSlot(BufferQueue::INVALID_BUFFER_SLOT),
-        mBuffer(nullptr),
-        mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2) {
+      : mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2) {
 }
 
 
@@ -145,6 +142,17 @@
 void Layer::onFirstRef() {}
 
 Layer::~Layer() {
+    sp<Client> c(mClientRef.promote());
+    if (c != 0) {
+        c->detachLayer(this);
+    }
+
+    for (auto& point : mRemoteSyncPoints) {
+        point->setTransactionApplied();
+    }
+    for (auto& point : mLocalSyncPoints) {
+        point->setFrameAvailable();
+    }
     mFrameTracker.logAndResetStats(mName);
 }
 
@@ -257,9 +265,9 @@
     if (!mCurrentCrop.isEmpty()) {
         // if the buffer crop is defined, we use that
         crop = mCurrentCrop;
-    } else if (getBE().mBuffer != NULL) {
+    } else if (getBE().compositionInfo.mBuffer != NULL) {
         // otherwise we use the whole buffer
-        crop = getBE().mBuffer->getBounds();
+        crop = getBE().compositionInfo.mBuffer->getBounds();
     } else {
         // if we don't have a buffer yet, we use an empty/invalid crop
         crop.makeInvalid();
@@ -277,6 +285,14 @@
     return Region(win).subtract(exclude).getBounds();
 }
 
+static FloatRect reduce(const FloatRect& win, const Region& exclude) {
+    if (CC_LIKELY(exclude.isEmpty())) {
+        return win;
+    }
+    // Convert through Rect (by rounding) for lack of FloatRegion
+    return Region(Rect{win}).subtract(exclude).getBounds().toFloatRect();
+}
+
 Rect Layer::computeScreenBounds(bool reduceTransparentRegion) const {
     const Layer::State& s(getDrawingState());
     Rect win(s.active.w, s.active.h);
@@ -315,12 +331,12 @@
     return win;
 }
 
-Rect Layer::computeBounds() const {
+FloatRect Layer::computeBounds() const {
     const Layer::State& s(getDrawingState());
     return computeBounds(s.activeTransparentRegion);
 }
 
-Rect Layer::computeBounds(const Region& activeTransparentRegion) const {
+FloatRect Layer::computeBounds(const Region& activeTransparentRegion) const {
     const Layer::State& s(getDrawingState());
     Rect win(s.active.w, s.active.h);
 
@@ -337,14 +353,16 @@
     }
 
     Transform t = getTransform();
+
+    FloatRect floatWin = win.toFloatRect();
     if (p != nullptr) {
-        win = t.transform(win);
-        win.intersect(bounds, &win);
-        win = t.inverse().transform(win);
+        floatWin = t.transform(floatWin);
+        floatWin = floatWin.intersect(bounds.toFloatRect());
+        floatWin = t.inverse().transform(floatWin);
     }
 
     // subtract the transparent region and snap to the bounds
-    return reduce(win, activeTransparentRegion);
+    return reduce(floatWin, activeTransparentRegion);
 }
 
 Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& hw) const {
@@ -520,7 +538,9 @@
                 Rect(activeCrop.right, activeCrop.top, s.active.w, activeCrop.bottom));
     }
 
-    Rect frame(t.transform(computeBounds(activeTransparentRegion)));
+    // computeBounds returns a FloatRect to provide more accuracy during the
+    // transformation. We then round upon constructing 'frame'.
+    Rect frame{t.transform(computeBounds(activeTransparentRegion))};
     if (!s.finalCrop.isEmpty()) {
         if (!frame.intersect(s.finalCrop, &frame)) {
             frame.clear();
@@ -799,7 +819,7 @@
     const Layer::State& s(getDrawingState());
     const Transform renderAreaTransform(renderArea.getTransform());
     const uint32_t height = renderArea.getHeight();
-    Rect win = computeBounds();
+    FloatRect win = computeBounds();
 
     vec2 lt = vec2(win.left, win.top);
     vec2 lb = vec2(win.left, win.bottom);
@@ -1002,9 +1022,9 @@
     // to the old buffer. However in the state where we don't have an old buffer
     // there is no such concern but we may still be being used as a parent layer.
     const bool resizePending = ((c.requested.w != c.active.w) || (c.requested.h != c.active.h)) &&
-            (getBE().mBuffer != nullptr);
+            (getBE().compositionInfo.mBuffer != nullptr);
     if (!isFixedSize()) {
-        if (resizePending && getBE().mSidebandStream == NULL) {
+        if (resizePending && getBE().compositionInfo.hwc.sidebandStream == nullptr) {
             flags |= eDontUpdateGeometryState;
         }
     }
@@ -1408,7 +1428,7 @@
     info.mMatrix[1][0] = ds.active.transform[1][0];
     info.mMatrix[1][1] = ds.active.transform[1][1];
     {
-        sp<const GraphicBuffer> buffer = getBE().mBuffer;
+        sp<const GraphicBuffer> buffer = getBE().compositionInfo.mBuffer;
         if (buffer != 0) {
             info.mActiveBufferWidth = buffer->getWidth();
             info.mActiveBufferHeight = buffer->getHeight();
@@ -1766,15 +1786,15 @@
         // for in the transform. We need to mirror this scaling in child surfaces
         // or we will break the contract where WM can treat child surfaces as
         // pixels in the parent surface.
-        if (p->isFixedSize() && p->getBE().mBuffer != nullptr) {
+        if (p->isFixedSize() && p->getBE().compositionInfo.mBuffer != nullptr) {
             int bufferWidth;
             int bufferHeight;
             if ((p->mCurrentTransform & NATIVE_WINDOW_TRANSFORM_ROT_90) == 0) {
-                bufferWidth = p->getBE().mBuffer->getWidth();
-                bufferHeight = p->getBE().mBuffer->getHeight();
+                bufferWidth = p->getBE().compositionInfo.mBuffer->getWidth();
+                bufferHeight = p->getBE().compositionInfo.mBuffer->getHeight();
             } else {
-                bufferHeight = p->getBE().mBuffer->getWidth();
-                bufferWidth = p->getBE().mBuffer->getHeight();
+                bufferHeight = p->getBE().compositionInfo.mBuffer->getWidth();
+                bufferWidth = p->getBE().compositionInfo.mBuffer->getHeight();
             }
             float sx = p->getDrawingState().active.w / static_cast<float>(bufferWidth);
             float sy = p->getDrawingState().active.h / static_cast<float>(bufferHeight);
@@ -1874,7 +1894,7 @@
         layerInfo->set_z_order_relative_of(zOrderRelativeOf->sequence);
     }
 
-    auto buffer = getBE().mBuffer;
+    auto buffer = getBE().compositionInfo.mBuffer;
     if (buffer != nullptr) {
         LayerProtoHelper::writeToProto(buffer, layerInfo->mutable_active_buffer());
     }
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 7c6bc59..e44ccf8 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -24,6 +24,7 @@
 #include <utils/String8.h>
 #include <utils/Timers.h>
 
+#include <ui/FloatRect.h>
 #include <ui/FrameStats.h>
 #include <ui/GraphicBuffer.h>
 #include <ui/PixelFormat.h>
@@ -31,6 +32,7 @@
 
 #include <gui/ISurfaceComposerClient.h>
 #include <gui/LayerState.h>
+#include <gui/BufferQueue.h>
 
 #include <list>
 
@@ -66,15 +68,37 @@
 
 // ---------------------------------------------------------------------------
 
+struct CompositionInfo {
+    HWC2::Composition compositionType;
+    sp<GraphicBuffer> mBuffer = nullptr;
+    int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
+    struct {
+        HWComposer* hwc;
+        sp<Fence> fence;
+        HWC2::BlendMode blendMode;
+        Rect displayFrame;
+        float alpha;
+        FloatRect sourceCrop;
+        HWC2::Transform transform;
+        int z;
+        int type;
+        int appId;
+        Region visibleRegion;
+        Region surfaceDamage;
+        sp<NativeHandle> sidebandStream;
+        android_dataspace dataspace;
+        hwc_color_t color;
+    } hwc;
+    struct {
+        RenderEngine* renderEngine;
+        Mesh* mesh;
+    } renderEngine;
+};
+
 class LayerBE {
 public:
     LayerBE();
 
-    // main thread
-    int mBufferSlot;
-    sp<GraphicBuffer> mBuffer;
-    sp<NativeHandle> mSidebandStream;
-
     // The mesh used to draw the layer in GLES composition mode
     Mesh mMesh;
 
@@ -102,6 +126,8 @@
     // case we need to keep track. In non-mirror mode, a layer will have only one
     // HWCInfo. This map key is a display layerStack.
     std::unordered_map<int32_t, HWCInfo> mHwcLayers;
+
+    CompositionInfo compositionInfo;
 };
 
 class Layer : public virtual RefBase {
@@ -278,8 +304,8 @@
     }
 
     void computeGeometry(const RenderArea& renderArea, Mesh& mesh, bool useIdentityTransform) const;
-    Rect computeBounds(const Region& activeTransparentRegion) const;
-    Rect computeBounds() const;
+    FloatRect computeBounds(const Region& activeTransparentRegion) const;
+    FloatRect computeBounds() const;
 
     int32_t getSequence() const { return sequence; }
 
diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h
index 828cd8b..40972aa 100644
--- a/services/surfaceflinger/LayerRejecter.h
+++ b/services/surfaceflinger/LayerRejecter.h
@@ -18,10 +18,10 @@
 #define ANDROID_LAYER_REJECTER_H
 
 #include "Layer.h"
-#include "SurfaceFlingerConsumer.h"
+#include "BufferLayerConsumer.h"
 
 namespace android {
-    class LayerRejecter : public SurfaceFlingerConsumer::BufferRejecter {
+    class LayerRejecter : public BufferLayerConsumer::BufferRejecter {
     public:
         LayerRejecter(Layer::State &front,
                       Layer::State &current,
diff --git a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
index 3161888..d1ee6f8 100644
--- a/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/GLES20RenderEngine.cpp
@@ -154,12 +154,12 @@
 void GLES20RenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
                                                   size_t hwh, bool yswap,
                                                   Transform::orientation_flags rotation) {
-    size_t l = sourceCrop.left;
-    size_t r = sourceCrop.right;
+    int32_t l = sourceCrop.left;
+    int32_t r = sourceCrop.right;
 
     // In GL, (0, 0) is the bottom-left corner, so flip y coordinates
-    size_t t = hwh - sourceCrop.top;
-    size_t b = hwh - sourceCrop.bottom;
+    int32_t t = hwh - sourceCrop.top;
+    int32_t b = hwh - sourceCrop.bottom;
 
     mat4 m;
     if (yswap) {
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.cpp b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
index 7ffcc96..e6e4df1 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.cpp
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
@@ -25,7 +25,22 @@
 
 ANDROID_SINGLETON_STATIC_INSTANCE(GLExtensions)
 
-GLExtensions::GLExtensions() : mHaveFramebufferObject(false) {}
+SortedVector<String8> GLExtensions::parseExtensionString(char const* extensions) {
+    SortedVector<String8> list;
+
+    char const* curr = extensions;
+    char const* head = curr;
+    do {
+        head = strchr(curr, ' ');
+        String8 s(curr, head ? head - curr : strlen(curr));
+        if (s.length()) {
+            list.add(s);
+        }
+        curr = head + 1;
+    } while (head);
+
+    return list;
+}
 
 void GLExtensions::initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer,
                                      GLubyte const* version, GLubyte const* extensions) {
@@ -33,21 +48,7 @@
     mRenderer = (char const*)renderer;
     mVersion = (char const*)version;
     mExtensions = (char const*)extensions;
-
-    char const* curr = (char const*)extensions;
-    char const* head = curr;
-    do {
-        head = strchr(curr, ' ');
-        String8 s(curr, head ? head - curr : strlen(curr));
-        if (s.length()) {
-            mExtensionList.add(s);
-        }
-        curr = head + 1;
-    } while (head);
-
-    if (hasExtension("GL_OES_framebuffer_object")) {
-        mHaveFramebufferObject = true;
-    }
+    mExtensionList = parseExtensionString(mExtensions);
 }
 
 bool GLExtensions::hasExtension(char const* extension) const {
@@ -67,9 +68,58 @@
     return mVersion.string();
 }
 
-char const* GLExtensions::getExtension() const {
+char const* GLExtensions::getExtensions() const {
     return mExtensions.string();
 }
 
+void GLExtensions::initWithEGLStrings(char const* eglVersion, char const* eglExtensions) {
+    mEGLVersion = eglVersion;
+    mEGLExtensions = eglExtensions;
+    mEGLExtensionList = parseExtensionString(mEGLExtensions);
+
+    // EGL_ANDROIDX_no_config_context is an experimental extension with no
+    // written specification. It will be replaced by something more formal.
+    // SurfaceFlinger is using it to allow a single EGLContext to render to
+    // both a 16-bit primary display framebuffer and a 32-bit virtual display
+    // framebuffer.
+    //
+    // EGL_KHR_no_config_context is official extension to allow creating a
+    // context that works with any surface of a display.
+    if (hasEGLExtension("EGL_ANDROIDX_no_config_context") ||
+        hasEGLExtension("EGL_KHR_no_config_context")) {
+        mHasNoConfigContext = true;
+    }
+
+    if (hasEGLExtension("EGL_ANDROID_native_fence_sync")) {
+        mHasNativeFenceSync = true;
+    }
+    if (hasEGLExtension("EGL_KHR_fence_sync")) {
+        mHasFenceSync = true;
+    }
+    if (hasEGLExtension("EGL_KHR_wait_sync")) {
+        mHasWaitSync = true;
+    }
+
+    if (hasEGLExtension("EGL_ANDROID_image_crop")) {
+        mHasImageCrop = true;
+    }
+    if (hasEGLExtension("EGL_EXT_protected_content")) {
+        mHasProtectedContent = true;
+    }
+}
+
+char const* GLExtensions::getEGLVersion() const {
+    return mEGLVersion.string();
+}
+
+char const* GLExtensions::getEGLExtensions() const {
+    return mEGLExtensions.string();
+}
+
+bool GLExtensions::hasEGLExtension(char const* extension) const {
+    const String8 s(extension);
+    return mEGLExtensionList.indexOf(s) >= 0;
+}
+
 // ---------------------------------------------------------------------------
 }; // namespace android
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.h b/services/surfaceflinger/RenderEngine/GLExtensions.h
index ee7b446..81078e0 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.h
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.h
@@ -35,7 +35,12 @@
 class GLExtensions : public Singleton<GLExtensions> {
     friend class Singleton<GLExtensions>;
 
-    bool mHaveFramebufferObject : 1;
+    bool mHasNoConfigContext = false;
+    bool mHasNativeFenceSync = false;
+    bool mHasFenceSync = false;
+    bool mHasWaitSync = false;
+    bool mHasImageCrop = false;
+    bool mHasProtectedContent = false;
 
     String8 mVendor;
     String8 mRenderer;
@@ -43,24 +48,38 @@
     String8 mExtensions;
     SortedVector<String8> mExtensionList;
 
+    String8 mEGLVersion;
+    String8 mEGLExtensions;
+    SortedVector<String8> mEGLExtensionList;
+
+    static SortedVector<String8> parseExtensionString(char const* extensions);
+
     GLExtensions(const GLExtensions&);
     GLExtensions& operator=(const GLExtensions&);
 
 protected:
-    GLExtensions();
+    GLExtensions() = default;
 
 public:
-    inline bool haveFramebufferObject() const { return mHaveFramebufferObject; }
+    bool hasNoConfigContext() const { return mHasNoConfigContext; }
+    bool hasNativeFenceSync() const { return mHasNativeFenceSync; }
+    bool hasFenceSync() const { return mHasFenceSync; }
+    bool hasWaitSync() const { return mHasWaitSync; }
+    bool hasImageCrop() const { return mHasImageCrop; }
+    bool hasProtectedContent() const { return mHasProtectedContent; }
 
     void initWithGLStrings(GLubyte const* vendor, GLubyte const* renderer, GLubyte const* version,
                            GLubyte const* extensions);
-
     char const* getVendor() const;
     char const* getRenderer() const;
     char const* getVersion() const;
-    char const* getExtension() const;
-
+    char const* getExtensions() const;
     bool hasExtension(char const* extension) const;
+
+    void initWithEGLStrings(char const* eglVersion, char const* eglExtensions);
+    char const* getEGLVersion() const;
+    char const* getEGLExtensions() const;
+    bool hasEGLExtension(char const* extension) const;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/Image.cpp b/services/surfaceflinger/RenderEngine/Image.cpp
new file mode 100644
index 0000000..1f8e75a
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Image.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2017 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 "Image.h"
+
+#include <vector>
+
+#include <log/log.h>
+
+#include "GLExtensions.h"
+#include "RenderEngine.h"
+
+namespace android {
+namespace RE {
+
+Image::Image(const RenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {}
+
+Image::~Image() {
+    setNativeWindowBuffer(nullptr, false, 0, 0);
+}
+
+static std::vector<EGLint> buildAttributeList(bool isProtected, int32_t cropWidth,
+                                              int32_t cropHeight) {
+    std::vector<EGLint> attrs;
+    attrs.reserve(16);
+
+    attrs.push_back(EGL_IMAGE_PRESERVED_KHR);
+    attrs.push_back(EGL_TRUE);
+
+    if (isProtected && GLExtensions::getInstance().hasProtectedContent()) {
+        attrs.push_back(EGL_PROTECTED_CONTENT_EXT);
+        attrs.push_back(EGL_TRUE);
+    }
+
+    if (cropWidth > 0 && cropHeight > 0) {
+        attrs.push_back(EGL_IMAGE_CROP_LEFT_ANDROID);
+        attrs.push_back(0);
+        attrs.push_back(EGL_IMAGE_CROP_TOP_ANDROID);
+        attrs.push_back(0);
+        attrs.push_back(EGL_IMAGE_CROP_RIGHT_ANDROID);
+        attrs.push_back(cropWidth);
+        attrs.push_back(EGL_IMAGE_CROP_BOTTOM_ANDROID);
+        attrs.push_back(cropHeight);
+    }
+
+    attrs.push_back(EGL_NONE);
+
+    return attrs;
+}
+
+bool Image::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
+                                  int32_t cropHeight) {
+    if (mEGLImage != EGL_NO_IMAGE_KHR) {
+        if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) {
+            ALOGE("failed to destroy image: %#x", eglGetError());
+        }
+        mEGLImage = EGL_NO_IMAGE_KHR;
+    }
+
+    if (buffer) {
+        std::vector<EGLint> attrs = buildAttributeList(isProtected, cropWidth, cropHeight);
+        mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+                                      static_cast<EGLClientBuffer>(buffer), attrs.data());
+        if (mEGLImage == EGL_NO_IMAGE_KHR) {
+            ALOGE("failed to create EGLImage: %#x", eglGetError());
+            return false;
+        }
+    }
+
+    return true;
+}
+
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/Image.h b/services/surfaceflinger/RenderEngine/Image.h
new file mode 100644
index 0000000..f55aa59
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/Image.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 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.
+ */
+
+#pragma once
+
+#include <cstdint>
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+struct ANativeWindowBuffer;
+
+namespace android {
+
+class RenderEngine;
+
+namespace RE {
+
+class Image {
+public:
+    Image(const RenderEngine& engine);
+    ~Image();
+
+    Image(const Image&) = delete;
+    Image& operator=(const Image&) = delete;
+
+    bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
+                               int32_t cropHeight);
+
+private:
+    // methods internal to RenderEngine
+    friend class android::RenderEngine;
+    EGLSurface getEGLImage() const { return mEGLImage; }
+
+    EGLDisplay mEGLDisplay;
+    EGLImageKHR mEGLImage = EGL_NO_IMAGE_KHR;
+};
+
+} // namespace RE
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 883ae26..314333f 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -20,6 +20,7 @@
 
 #include "GLES20RenderEngine.h"
 #include "GLExtensions.h"
+#include "Image.h"
 #include "Mesh.h"
 #include "RenderEngine.h"
 
@@ -32,19 +33,6 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-static bool findExtension(const char* exts, const char* name) {
-    if (!exts) return false;
-    size_t len = strlen(name);
-
-    const char* pos = exts;
-    while ((pos = strstr(pos, name)) != NULL) {
-        if (pos[len] == '\0' || pos[len] == ' ') return true;
-        pos += len;
-    }
-
-    return false;
-}
-
 std::unique_ptr<RenderEngine> RenderEngine::create(int hwcFormat, uint32_t featureFlags) {
     // initialize EGL for the default display
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
@@ -52,22 +40,14 @@
         LOG_ALWAYS_FATAL("failed to initialize EGL");
     }
 
-    // EGL_ANDROIDX_no_config_context is an experimental extension with no
-    // written specification. It will be replaced by something more formal.
-    // SurfaceFlinger is using it to allow a single EGLContext to render to
-    // both a 16-bit primary display framebuffer and a 32-bit virtual display
-    // framebuffer.
-    //
-    // EGL_KHR_no_config_context is official extension to allow creating a
-    // context that works with any surface of a display.
-    //
+    GLExtensions& extensions(GLExtensions::getInstance());
+    extensions.initWithEGLStrings(eglQueryStringImplementationANDROID(display, EGL_VERSION),
+                                  eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS));
+
     // The code assumes that ES2 or later is available if this extension is
     // supported.
     EGLConfig config = EGL_NO_CONFIG;
-    if (!findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),
-                       "EGL_ANDROIDX_no_config_context") &&
-        !findExtension(eglQueryStringImplementationANDROID(display, EGL_EXTENSIONS),
-                       "EGL_KHR_no_config_context")) {
+    if (!extensions.hasNoConfigContext()) {
         config = chooseEglConfig(display, hwcFormat, /*logConfig*/ true);
     }
 
@@ -117,7 +97,6 @@
     EGLBoolean success = eglMakeCurrent(display, dummy, dummy, ctxt);
     LOG_ALWAYS_FATAL_IF(!success, "can't make dummy pbuffer current");
 
-    GLExtensions& extensions(GLExtensions::getInstance());
     extensions.initWithGLStrings(glGetString(GL_VENDOR), glGetString(GL_RENDERER),
                                  glGetString(GL_VERSION), glGetString(GL_EXTENSIONS));
 
@@ -142,7 +121,7 @@
     ALOGI("vendor    : %s", extensions.getVendor());
     ALOGI("renderer  : %s", extensions.getRenderer());
     ALOGI("version   : %s", extensions.getVersion());
-    ALOGI("extensions: %s", extensions.getExtension());
+    ALOGI("extensions: %s", extensions.getExtensions());
     ALOGI("GL_MAX_TEXTURE_SIZE = %zu", engine->getMaxTextureSize());
     ALOGI("GL_MAX_VIEWPORT_DIMS = %zu", engine->getMaxViewportDims());
 
@@ -174,6 +153,14 @@
     return mEGLConfig;
 }
 
+bool RenderEngine::supportsImageCrop() const {
+    return GLExtensions::getInstance().hasImageCrop();
+}
+
+bool RenderEngine::isCurrent() const {
+    return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
+}
+
 bool RenderEngine::setCurrentSurface(const RE::Surface& surface) {
     bool success = true;
     EGLSurface eglSurface = surface.getEGLSurface();
@@ -191,6 +178,88 @@
     eglMakeCurrent(mEGLDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
 }
 
+base::unique_fd RenderEngine::flush() {
+    if (!GLExtensions::getInstance().hasNativeFenceSync()) {
+        return base::unique_fd();
+    }
+
+    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+    if (sync == EGL_NO_SYNC_KHR) {
+        ALOGW("failed to create EGL native fence sync: %#x", eglGetError());
+        return base::unique_fd();
+    }
+
+    // native fence fd will not be populated until flush() is done.
+    glFlush();
+
+    // get the fence fd
+    base::unique_fd fenceFd(eglDupNativeFenceFDANDROID(mEGLDisplay, sync));
+    eglDestroySyncKHR(mEGLDisplay, sync);
+    if (fenceFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
+        ALOGW("failed to dup EGL native fence sync: %#x", eglGetError());
+    }
+
+    return fenceFd;
+}
+
+bool RenderEngine::finish() {
+    if (!GLExtensions::getInstance().hasFenceSync()) {
+        ALOGW("no synchronization support");
+        return false;
+    }
+
+    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
+    if (sync == EGL_NO_SYNC_KHR) {
+        ALOGW("failed to create EGL fence sync: %#x", eglGetError());
+        return false;
+    }
+
+    EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
+                                         2000000000 /*2 sec*/);
+    EGLint error = eglGetError();
+    eglDestroySyncKHR(mEGLDisplay, sync);
+    if (result != EGL_CONDITION_SATISFIED_KHR) {
+        if (result == EGL_TIMEOUT_EXPIRED_KHR) {
+            ALOGW("fence wait timed out");
+        } else {
+            ALOGW("error waiting on EGL fence: %#x", error);
+        }
+        return false;
+    }
+
+    return true;
+}
+
+bool RenderEngine::waitFence(base::unique_fd fenceFd) {
+    if (!GLExtensions::getInstance().hasNativeFenceSync() ||
+        !GLExtensions::getInstance().hasWaitSync()) {
+        return false;
+    }
+
+    EGLint attribs[] = {EGL_SYNC_NATIVE_FENCE_FD_ANDROID, fenceFd, EGL_NONE};
+    EGLSyncKHR sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, attribs);
+    if (sync == EGL_NO_SYNC_KHR) {
+        ALOGE("failed to create EGL native fence sync: %#x", eglGetError());
+        return false;
+    }
+
+    // fenceFd is now owned by EGLSync
+    (void)fenceFd.release();
+
+    // XXX: The spec draft is inconsistent as to whether this should return an
+    // EGLint or void.  Ignore the return value for now, as it's not strictly
+    // needed.
+    eglWaitSyncKHR(mEGLDisplay, sync, 0);
+    EGLint error = eglGetError();
+    eglDestroySyncKHR(mEGLDisplay, sync);
+    if (error != EGL_SUCCESS) {
+        ALOGE("failed to wait for EGL native fence sync: %#x", error);
+        return false;
+    }
+
+    return true;
+}
+
 void RenderEngine::checkErrors() const {
     do {
         // there could be more than one error flag
@@ -242,52 +311,6 @@
     drawMesh(mesh);
 }
 
-int RenderEngine::flush(bool wait) {
-    // Attempt to create a sync khr object that can produce a sync point. If that
-    // isn't available, create a non-dupable sync object in the fallback path and
-    // wait on it directly.
-    EGLSyncKHR sync;
-    if (!wait) {
-        EGLint syncFd = EGL_NO_NATIVE_FENCE_FD_ANDROID;
-
-        sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
-        if (sync != EGL_NO_SYNC_KHR) {
-            // native fence fd will not be populated until flush() is done.
-            glFlush();
-
-            // get the sync fd
-            syncFd = eglDupNativeFenceFDANDROID(mEGLDisplay, sync);
-            if (syncFd == EGL_NO_NATIVE_FENCE_FD_ANDROID) {
-                ALOGW("failed to dup sync khr object");
-            }
-
-            eglDestroySyncKHR(mEGLDisplay, sync);
-        }
-
-        if (syncFd != EGL_NO_NATIVE_FENCE_FD_ANDROID) {
-            return syncFd;
-        }
-    }
-
-    // fallback or explicit wait
-    sync = eglCreateSyncKHR(mEGLDisplay, EGL_SYNC_FENCE_KHR, NULL);
-    if (sync != EGL_NO_SYNC_KHR) {
-        EGLint result = eglClientWaitSyncKHR(mEGLDisplay, sync, EGL_SYNC_FLUSH_COMMANDS_BIT_KHR,
-                                             2000000000 /*2 sec*/);
-        EGLint eglErr = eglGetError();
-        if (result == EGL_TIMEOUT_EXPIRED_KHR) {
-            ALOGW("fence wait timed out");
-        } else {
-            ALOGW_IF(eglErr != EGL_SUCCESS, "error waiting on EGL fence: %#x", eglErr);
-        }
-        eglDestroySyncKHR(mEGLDisplay, sync);
-    } else {
-        ALOGW("error creating EGL fence: %#x", eglGetError());
-    }
-
-    return -1;
-}
-
 void RenderEngine::clearWithColor(float red, float green, float blue, float alpha) {
     glClearColor(red, green, blue, alpha);
     glClear(GL_COLOR_BUFFER_BIT);
@@ -310,19 +333,28 @@
     glDeleteTextures(count, names);
 }
 
+void RenderEngine::bindExternalTextureImage(uint32_t texName, const RE::Image& image) {
+    const GLenum target = GL_TEXTURE_EXTERNAL_OES;
+
+    glBindTexture(target, texName);
+    if (image.getEGLImage() != EGL_NO_IMAGE_KHR) {
+        glEGLImageTargetTexture2DOES(target, static_cast<GLeglImageOES>(image.getEGLImage()));
+    }
+}
+
 void RenderEngine::readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels) {
     glReadPixels(l, b, w, h, GL_RGBA, GL_UNSIGNED_BYTE, pixels);
 }
 
 void RenderEngine::dump(String8& result) {
-    result.appendFormat("EGL implementation : %s\n",
-                        eglQueryStringImplementationANDROID(mEGLDisplay, EGL_VERSION));
-    result.appendFormat("%s\n", eglQueryStringImplementationANDROID(mEGLDisplay, EGL_EXTENSIONS));
-
     const GLExtensions& extensions(GLExtensions::getInstance());
+
+    result.appendFormat("EGL implementation : %s\n", extensions.getEGLVersion());
+    result.appendFormat("%s\n", extensions.getEGLExtensions());
+
     result.appendFormat("GLES: %s, %s, %s\n", extensions.getVendor(), extensions.getRenderer(),
                         extensions.getVersion());
-    result.appendFormat("%s\n", extensions.getExtension());
+    result.appendFormat("%s\n", extensions.getExtensions());
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 3847347..f886919 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -25,6 +25,7 @@
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
 #include <Transform.h>
+#include <android-base/unique_fd.h>
 #include <gui/SurfaceControl.h>
 #include <math/mat4.h>
 
@@ -43,8 +44,9 @@
 class Texture;
 
 namespace RE {
+class Image;
 class Surface;
-}
+} // namespace RE
 
 class RenderEngine {
     enum GlesVersion {
@@ -82,9 +84,26 @@
     // dump the extension strings. always call the base class.
     virtual void dump(String8& result);
 
+    bool supportsImageCrop() const;
+
+    bool isCurrent() const;
+    bool setCurrentSurface(const RE::Surface& surface);
+    void resetCurrentSurface();
+
+    // synchronization
+
+    // flush submits RenderEngine command stream for execution and returns a
+    // native fence fd that is signaled when the execution has completed.  It
+    // returns -1 on errors.
+    base::unique_fd flush();
+    // finish waits until RenderEngine command stream has been executed.  It
+    // returns false on errors.
+    bool finish();
+    // waitFence inserts a wait on an external fence fd to RenderEngine
+    // command stream.  It returns false on errors.
+    bool waitFence(base::unique_fd fenceFd);
+
     // helpers
-    // flush returns -1 or a valid native fence fd owned by the caller
-    int flush(bool wait);
     void clearWithColor(float red, float green, float blue, float alpha);
     void fillRegionWithColor(const Region& region, uint32_t height, float red, float green,
                              float blue, float alpha);
@@ -94,6 +113,7 @@
     void disableScissor();
     void genTextures(size_t count, uint32_t* names);
     void deleteTextures(size_t count, uint32_t const* names);
+    void bindExternalTextureImage(uint32_t texName, const RE::Image& image);
     void readPixels(size_t l, size_t b, size_t w, size_t h, uint32_t* pixels);
 
     class BindNativeBufferAsFramebuffer {
@@ -108,9 +128,6 @@
         int getStatus() const;
     };
 
-    bool setCurrentSurface(const RE::Surface& surface);
-    void resetCurrentSurface();
-
     // set-up
     virtual void checkErrors() const;
     virtual void setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop, size_t hwh,
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 142892e..a5b92b5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -153,6 +153,15 @@
     return std::string(value) == "true";
 }
 
+SurfaceFlingerBE::SurfaceFlingerBE()
+      : mHwcServiceName(getHwcServiceName()),
+        mRenderEngine(nullptr),
+        mFrameBuckets(),
+        mTotalTime(0),
+        mLastSwapTime(0),
+        mComposerSequenceId(0) {
+}
+
 SurfaceFlinger::SurfaceFlinger()
     :   BnSurfaceComposer(),
         mTransactionFlags(0),
@@ -161,8 +170,6 @@
         mLayersRemoved(false),
         mLayersAdded(false),
         mRepaintEverything(0),
-        mHwcServiceName(getHwcServiceName()),
-        mRenderEngine(nullptr),
         mBootTime(systemTime()),
         mBuiltinDisplays(),
         mVisibleRegionsDirty(false),
@@ -184,13 +191,9 @@
         mHWVsyncAvailable(false),
         mHasColorMatrix(false),
         mHasPoweredOff(false),
-        mFrameBuckets(),
-        mTotalTime(0),
-        mLastSwapTime(0),
         mNumLayers(0),
         mVrFlingerRequestsDisplay(false),
-        mMainThreadId(std::this_thread::get_id()),
-        mComposerSequenceId(0)
+        mMainThreadId(std::this_thread::get_id())
 {
     ALOGI("SurfaceFlinger is starting");
 
@@ -225,7 +228,7 @@
     hasWideColorDisplay =
             getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::hasWideColorDisplay>(false);
 
-    mPrimaryDispSync.init(hasSyncFramework, dispSyncPresentTimeOffset);
+    mPrimaryDispSync.init(SurfaceFlinger::hasSyncFramework, SurfaceFlinger::dispSyncPresentTimeOffset);
 
     // debugging stuff...
     char value[PROPERTY_VALUE_MAX];
@@ -588,11 +591,11 @@
     Mutex::Autolock _l(mStateLock);
 
     // start the EventThread
-    sp<VSyncSource> vsyncSrc = new DispSyncSource(&mPrimaryDispSync,
-            vsyncPhaseOffsetNs, true, "app");
+    sp<VSyncSource> vsyncSrc =
+            new DispSyncSource(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs, true, "app");
     mEventThread = new EventThread(vsyncSrc, *this, false);
-    sp<VSyncSource> sfVsyncSrc = new DispSyncSource(&mPrimaryDispSync,
-            sfVsyncPhaseOffsetNs, true, "sf");
+    sp<VSyncSource> sfVsyncSrc =
+            new DispSyncSource(&mPrimaryDispSync, SurfaceFlinger::sfVsyncPhaseOffsetNs, true, "sf");
     mSFEventThread = new EventThread(sfVsyncSrc, *this, true);
     mEventQueue.setEventThread(mSFEventThread);
 
@@ -607,14 +610,14 @@
     }
 
     // Get a RenderEngine for the given display / config (can't fail)
-    mRenderEngine = RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,
+    getBE().mRenderEngine = RenderEngine::create(HAL_PIXEL_FORMAT_RGBA_8888,
             hasWideColorDisplay ? RenderEngine::WIDE_COLOR_SUPPORT : 0);
-    LOG_ALWAYS_FATAL_IF(mRenderEngine == nullptr, "couldn't create RenderEngine");
+    LOG_ALWAYS_FATAL_IF(getBE().mRenderEngine == nullptr, "couldn't create RenderEngine");
 
     LOG_ALWAYS_FATAL_IF(mVrFlingerRequestsDisplay,
             "Starting with vr flinger active is not currently supported.");
-    mHwc.reset(new HWComposer(mHwcServiceName));
-    mHwc->registerCallback(this, mComposerSequenceId);
+    getBE().mHwc.reset(new HWComposer(getBE().mHwcServiceName));
+    getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId);
 
     if (useVrFlinger) {
         auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
@@ -631,8 +634,8 @@
             });
             postMessageAsync(message);
         };
-        mVrFlinger = dvr::VrFlinger::Create(mHwc->getComposer(),
-                mHwc->getHwcDisplayId(HWC_DISPLAY_PRIMARY).value_or(0),
+        mVrFlinger = dvr::VrFlinger::Create(getBE().mHwc->getComposer(),
+                getBE().mHwc->getHwcDisplayId(HWC_DISPLAY_PRIMARY).value_or(0),
                 vrFlingerRequestDisplayCallback);
         if (!mVrFlinger) {
             ALOGE("Failed to start vrflinger");
@@ -648,7 +651,7 @@
     // set initial conditions (e.g. unblank default device)
     initializeDisplays();
 
-    mRenderEngine->primeCache();
+    getBE().mRenderEngine->primeCache();
 
     // Inform native graphics APIs whether the present timestamp is supported:
     if (getHwComposer().hasCapability(
@@ -690,11 +693,11 @@
 }
 
 size_t SurfaceFlinger::getMaxTextureSize() const {
-    return mRenderEngine->getMaxTextureSize();
+    return getBE().mRenderEngine->getMaxTextureSize();
 }
 
 size_t SurfaceFlinger::getMaxViewportDims() const {
-    return mRenderEngine->getMaxViewportDims();
+    return getBE().mRenderEngine->getMaxViewportDims();
 }
 
 // ----------------------------------------------------------------------------
@@ -1042,7 +1045,7 @@
     }
 
     std::unique_ptr<HdrCapabilities> capabilities =
-            mHwc->getHdrCapabilities(displayDevice->getHwcDisplayId());
+            getBE().mHwc->getHdrCapabilities(displayDevice->getHwcDisplayId());
     if (capabilities) {
         std::swap(*outCapabilities, *capabilities);
     } else {
@@ -1190,7 +1193,7 @@
         return;
     }
 
-    const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
     const nsecs_t period = activeConfig->getVsyncPeriod();
 
     mPrimaryDispSync.reset();
@@ -1233,12 +1236,12 @@
         hwc2_display_t displayId, int64_t timestamp) {
     Mutex::Autolock lock(mStateLock);
     // Ignore any vsyncs from a previous hardware composer.
-    if (sequenceId != mComposerSequenceId) {
+    if (sequenceId != getBE().mComposerSequenceId) {
         return;
     }
 
     int32_t type;
-    if (!mHwc->onVsync(displayId, timestamp, &type)) {
+    if (!getBE().mHwc->onVsync(displayId, timestamp, &type)) {
         return;
     }
 
@@ -1259,8 +1262,8 @@
 }
 
 void SurfaceFlinger::getCompositorTiming(CompositorTiming* compositorTiming) {
-    std::lock_guard<std::mutex> lock(mCompositorTimingLock);
-    *compositorTiming = mCompositorTiming;
+    std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
+    *compositorTiming = getBE().mCompositorTiming;
 }
 
 void SurfaceFlinger::createDefaultDisplayDevice() {
@@ -1274,7 +1277,7 @@
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer);
 
-    sp<FramebufferSurface> fbs = new FramebufferSurface(*mHwc, type, consumer);
+    sp<FramebufferSurface> fbs = new FramebufferSurface(*getBE().mHwc, type, consumer);
 
     bool hasWideColorModes = false;
     std::vector<android_color_mode_t> modes = getHwComposer().getColorModes(type);
@@ -1326,20 +1329,20 @@
             std::this_thread::get_id() != mMainThreadId);
 
     if (primaryDisplay) {
-        mHwc->onHotplug(display, connection);
+        getBE().mHwc->onHotplug(display, connection);
         if (!mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY].get()) {
             createBuiltinDisplayLocked(DisplayDevice::DISPLAY_PRIMARY);
         }
         createDefaultDisplayDevice();
     } else {
-        if (sequenceId != mComposerSequenceId) {
+        if (sequenceId != getBE().mComposerSequenceId) {
             return;
         }
-        if (mHwc->isUsingVrComposer()) {
+        if (getBE().mHwc->isUsingVrComposer()) {
             ALOGE("External displays are not supported by the vr hardware composer.");
             return;
         }
-        mHwc->onHotplug(display, connection);
+        getBE().mHwc->onHotplug(display, connection);
         auto type = DisplayDevice::DISPLAY_EXTERNAL;
         if (connection == HWC2::Connection::Connected) {
             createBuiltinDisplayLocked(type);
@@ -1356,7 +1359,7 @@
 void SurfaceFlinger::onRefreshReceived(int sequenceId,
                                        hwc2_display_t /*display*/) {
     Mutex::Autolock lock(mStateLock);
-    if (sequenceId != mComposerSequenceId) {
+    if (sequenceId != getBE().mComposerSequenceId) {
         return;
     }
     repaintEverythingLocked();
@@ -1385,11 +1388,11 @@
     if (!mVrFlinger)
         return;
     bool vrFlingerRequestsDisplay = mVrFlingerRequestsDisplay;
-    if (vrFlingerRequestsDisplay == mHwc->isUsingVrComposer()) {
+    if (vrFlingerRequestsDisplay == getBE().mHwc->isUsingVrComposer()) {
         return;
     }
 
-    if (vrFlingerRequestsDisplay && !mHwc->getComposer()->isRemote()) {
+    if (vrFlingerRequestsDisplay && !getBE().mHwc->getComposer()->isRemote()) {
         ALOGE("Vr flinger is only supported for remote hardware composer"
               " service connections. Ignoring request to transition to vr"
               " flinger.");
@@ -1407,13 +1410,12 @@
     }
 
     resetDisplayState();
-    mHwc.reset();  // Delete the current instance before creating the new one
-    mHwc.reset(new HWComposer(
-            vrFlingerRequestsDisplay ? "vr" : mHwcServiceName));
-    mHwc->registerCallback(this, ++mComposerSequenceId);
+    getBE().mHwc.reset(); // Delete the current instance before creating the new one
+    getBE().mHwc.reset(new HWComposer(vrFlingerRequestsDisplay ? "vr" : getBE().mHwcServiceName));
+    getBE().mHwc->registerCallback(this, ++getBE().mComposerSequenceId);
 
-    LOG_ALWAYS_FATAL_IF(!mHwc->getComposer()->isRemote(),
-            "Switched to non-remote hardware composer");
+    LOG_ALWAYS_FATAL_IF(!getBE().mHwc->getComposer()->isRemote(),
+                        "Switched to non-remote hardware composer");
 
     if (vrFlingerRequestsDisplay) {
         mVrFlinger->GrantDisplayOwnership();
@@ -1430,7 +1432,7 @@
     setPowerModeInternal(hw, currentDisplayPowerMode, /*stateLockHeld*/ true);
 
     // Reset the timing values to account for the period of the swapped in HWC
-    const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
     const nsecs_t period = activeConfig->getVsyncPeriod();
     mAnimFrameTracker.setDisplayRefreshPeriod(period);
 
@@ -1508,13 +1510,13 @@
     doComposition();
     postComposition(refreshStartTime);
 
-    mPreviousPresentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
+    mPreviousPresentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
 
     mHadClientComposition = false;
     for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
         const sp<DisplayDevice>& displayDevice = mDisplays[displayId];
         mHadClientComposition = mHadClientComposition ||
-                mHwc->hasClientComposition(displayDevice->getHwcDisplayId());
+                getBE().mHwc->hasClientComposition(displayDevice->getHwcDisplayId());
     }
 
     mLayersWithQueuedFrames.clear();
@@ -1558,9 +1560,11 @@
             continue;
         }
 
-        status_t result = displayDevice->prepareFrame(*mHwc);
-        ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:"
-                " %d (%s)", displayId, result, strerror(-result));
+        status_t result = displayDevice->prepareFrame(*getBE().mHwc);
+        ALOGE_IF(result != NO_ERROR,
+                 "prepareFrame for display %zd failed:"
+                 " %d (%s)",
+                 displayId, result, strerror(-result));
     }
 }
 
@@ -1594,10 +1598,10 @@
         std::shared_ptr<FenceTime>& presentFenceTime) {
     // Update queue of past composite+present times and determine the
     // most recently known composite to present latency.
-    mCompositePresentTimes.push({compositeTime, presentFenceTime});
+    getBE().mCompositePresentTimes.push({compositeTime, presentFenceTime});
     nsecs_t compositeToPresentLatency = -1;
-    while (!mCompositePresentTimes.empty()) {
-        CompositePresentTime& cpt = mCompositePresentTimes.front();
+    while (!getBE().mCompositePresentTimes.empty()) {
+        SurfaceFlingerBE::CompositePresentTime& cpt = getBE().mCompositePresentTimes.front();
         // Cached values should have been updated before calling this method,
         // which helps avoid duplicate syscalls.
         nsecs_t displayTime = cpt.display->getCachedSignalTime();
@@ -1605,12 +1609,12 @@
             break;
         }
         compositeToPresentLatency = displayTime - cpt.composite;
-        mCompositePresentTimes.pop();
+        getBE().mCompositePresentTimes.pop();
     }
 
     // Don't let mCompositePresentTimes grow unbounded, just in case.
-    while (mCompositePresentTimes.size() > 16) {
-        mCompositePresentTimes.pop();
+    while (getBE().mCompositePresentTimes.size() > 16) {
+        getBE().mCompositePresentTimes.pop();
     }
 
     setCompositorTimingSnapped(
@@ -1642,10 +1646,10 @@
     nsecs_t snappedCompositeToPresentLatency = (extraVsyncs > 0) ?
             idealLatency + (extraVsyncs * vsyncInterval) : idealLatency;
 
-    std::lock_guard<std::mutex> lock(mCompositorTimingLock);
-    mCompositorTiming.deadline = vsyncPhase - idealLatency;
-    mCompositorTiming.interval = vsyncInterval;
-    mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
+    std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
+    getBE().mCompositorTiming.deadline = vsyncPhase - idealLatency;
+    getBE().mCompositorTiming.interval = vsyncInterval;
+    getBE().mCompositorTiming.presentLatency = snappedCompositeToPresentLatency;
 }
 
 void SurfaceFlinger::postComposition(nsecs_t refreshStartTime)
@@ -1662,20 +1666,20 @@
     // |mStateLock| not needed as we are on the main thread
     const sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
 
-    mGlCompositionDoneTimeline.updateSignalTimes();
+    getBE().mGlCompositionDoneTimeline.updateSignalTimes();
     std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
-    if (mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
+    if (getBE().mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
         glCompositionDoneFenceTime =
                 std::make_shared<FenceTime>(hw->getClientTargetAcquireFence());
-        mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
+        getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
     } else {
         glCompositionDoneFenceTime = FenceTime::NO_FENCE;
     }
 
-    mDisplayTimeline.updateSignalTimes();
-    sp<Fence> presentFence = mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
+    getBE().mDisplayTimeline.updateSignalTimes();
+    sp<Fence> presentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
     auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
-    mDisplayTimeline.push(presentFenceTime);
+    getBE().mDisplayTimeline.push(presentFenceTime);
 
     nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
     nsecs_t vsyncInterval = mPrimaryDispSync.getPeriod();
@@ -1687,8 +1691,8 @@
         vsyncPhase, vsyncInterval, refreshStartTime, presentFenceTime);
     CompositorTiming compositorTiming;
     {
-        std::lock_guard<std::mutex> lock(mCompositorTimingLock);
-        compositorTiming = mCompositorTiming;
+        std::lock_guard<std::mutex> lock(getBE().mCompositorTimingLock);
+        compositorTiming = getBE().mCompositorTiming;
     }
 
     mDrawingState.traverseInZOrder([&](Layer* layer) {
@@ -1724,7 +1728,7 @@
             // The HWC doesn't support present fences, so use the refresh
             // timestamp instead.
             nsecs_t presentTime =
-                    mHwc->getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+                    getBE().mHwc->getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
             mAnimFrameTracker.setActualPresentTime(presentTime);
         }
         mAnimFrameTracker.advanceFrame();
@@ -1738,16 +1742,16 @@
     if (mHasPoweredOff) {
         mHasPoweredOff = false;
     } else {
-        nsecs_t elapsedTime = currentTime - mLastSwapTime;
+        nsecs_t elapsedTime = currentTime - getBE().mLastSwapTime;
         size_t numPeriods = static_cast<size_t>(elapsedTime / vsyncInterval);
-        if (numPeriods < NUM_BUCKETS - 1) {
-            mFrameBuckets[numPeriods] += elapsedTime;
+        if (numPeriods < SurfaceFlingerBE::NUM_BUCKETS - 1) {
+            getBE().mFrameBuckets[numPeriods] += elapsedTime;
         } else {
-            mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime;
+            getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] += elapsedTime;
         }
-        mTotalTime += elapsedTime;
+        getBE().mTotalTime += elapsedTime;
     }
-    mLastSwapTime = currentTime;
+    getBE().mLastSwapTime = currentTime;
 }
 
 void SurfaceFlinger::rebuildLayerStacks() {
@@ -1923,7 +1927,7 @@
                 for (size_t i = 0; i < currentLayers.size(); i++) {
                     const auto& layer = currentLayers[i];
                     if (!layer->hasHwcLayer(hwcId)) {
-                        if (!layer->createHwcLayer(mHwc.get(), hwcId)) {
+                        if (!layer->createHwcLayer(getBE().mHwc.get(), hwcId)) {
                             layer->forceClientComposition(hwcId);
                             continue;
                         }
@@ -1950,7 +1954,7 @@
             continue;
         }
         if (colorMatrix != mPreviousColorMatrix) {
-            status_t result = mHwc->setColorTransform(hwcId, colorMatrix);
+            status_t result = getBE().mHwc->setColorTransform(hwcId, colorMatrix);
             ALOGE_IF(result != NO_ERROR, "Failed to set color transform on "
                     "display %zd: %d", displayId, result);
         }
@@ -1988,7 +1992,7 @@
             continue;
         }
 
-        status_t result = displayDevice->prepareFrame(*mHwc);
+        status_t result = displayDevice->prepareFrame(*getBE().mHwc);
         ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:"
                 " %d (%s)", displayId, result, strerror(-result));
     }
@@ -2030,7 +2034,7 @@
         }
         const auto hwcId = displayDevice->getHwcDisplayId();
         if (hwcId >= 0) {
-            mHwc->presentAndGetReleaseFences(hwcId);
+            getBE().mHwc->presentAndGetReleaseFences(hwcId);
         }
         displayDevice->onSwapBuffersCompleted();
         displayDevice->makeCurrent();
@@ -2039,7 +2043,7 @@
             // by HWC only when the release fence from this frame (if any) is
             // signaled.  Always get the release fence from HWC first.
             auto hwcLayer = layer->getHwcLayer(hwcId);
-            sp<Fence> releaseFence = mHwc->getLayerReleaseFence(hwcId, hwcLayer);
+            sp<Fence> releaseFence = getBE().mHwc->getLayerReleaseFence(hwcId, hwcLayer);
 
             // If the layer was client composited in the previous frame, we
             // need to merge with the previous client target acquire fence.
@@ -2058,14 +2062,14 @@
         // displayDevice->getVisibleLayersSortedByZ.  The best we can do is to
         // supply them with the present fence.
         if (!displayDevice->getLayersNeedingFences().isEmpty()) {
-            sp<Fence> presentFence = mHwc->getPresentFence(hwcId);
+            sp<Fence> presentFence = getBE().mHwc->getPresentFence(hwcId);
             for (auto& layer : displayDevice->getLayersNeedingFences()) {
                 layer->onLayerDisplayed(presentFence);
             }
         }
 
         if (hwcId >= 0) {
-            mHwc->clearReleaseFences(hwcId);
+            getBE().mHwc->clearReleaseFences(hwcId);
         }
     }
 
@@ -2150,7 +2154,7 @@
             // (ie: in drawing state but not in current state)
             // also handle displays that changed
             // (ie: displays that are in both lists)
-            for (size_t i=0 ; i<dc ; i++) {
+            for (size_t i=0 ; i<dc ;) {
                 const ssize_t j = curr.indexOfKey(draw.keyAt(i));
                 if (j < 0) {
                     // in drawing state but not in current state
@@ -2185,7 +2189,7 @@
                             hw->disconnect(getHwComposer());
                         mDisplays.removeItem(display);
                         mDrawingState.displays.removeItemsAt(i);
-                        dc--; i--;
+                        dc--;
                         // at this point we must loop to the next item
                         continue;
                     }
@@ -2207,6 +2211,7 @@
                         }
                     }
                 }
+                ++i;
             }
 
             // find displays that were added
@@ -2229,7 +2234,7 @@
                         if (state.surface != NULL) {
 
                             // Allow VR composer to use virtual displays.
-                            if (mUseHwcVirtualDisplays || mHwc->isUsingVrComposer()) {
+                            if (mUseHwcVirtualDisplays || getBE().mHwc->isUsingVrComposer()) {
                                 int width = 0;
                                 int status = state.surface->query(
                                         NATIVE_WINDOW_WIDTH, &width);
@@ -2248,14 +2253,14 @@
                                 auto format = static_cast<android_pixel_format_t>(
                                         intFormat);
 
-                                mHwc->allocateVirtualDisplay(width, height, &format,
+                                getBE().mHwc->allocateVirtualDisplay(width, height, &format,
                                         &hwcId);
                             }
 
                             // TODO: Plumb requested format back up to consumer
 
                             sp<VirtualDisplaySurface> vds =
-                                    new VirtualDisplaySurface(*mHwc,
+                                    new VirtualDisplaySurface(*getBE().mHwc,
                                             hwcId, state.surface, bqProducer,
                                             bqConsumer, state.displayName);
 
@@ -2269,7 +2274,7 @@
                                 state.surface.get());
 
                         hwcId = state.type;
-                        dispSurface = new FramebufferSurface(*mHwc, hwcId, bqConsumer);
+                        dispSurface = new FramebufferSurface(*getBE().mHwc, hwcId, bqConsumer);
                         producer = bqProducer;
                     }
 
@@ -2657,20 +2662,20 @@
     const auto hwcId = displayDevice->getHwcDisplayId();
 
     mat4 oldColorMatrix;
-    const bool applyColorMatrix = !mHwc->hasDeviceComposition(hwcId) &&
-            !mHwc->hasCapability(HWC2::Capability::SkipClientColorTransform);
+    const bool applyColorMatrix = !getBE().mHwc->hasDeviceComposition(hwcId) &&
+            !getBE().mHwc->hasCapability(HWC2::Capability::SkipClientColorTransform);
     if (applyColorMatrix) {
         mat4 colorMatrix = mColorMatrix * mDaltonizer();
         oldColorMatrix = getRenderEngine().setupColorTransform(colorMatrix);
     }
 
-    bool hasClientComposition = mHwc->hasClientComposition(hwcId);
+    bool hasClientComposition = getBE().mHwc->hasClientComposition(hwcId);
     if (hasClientComposition) {
         ALOGV("hasClientComposition");
 
-        mRenderEngine->setWideColor(
+        getBE().mRenderEngine->setWideColor(
                 displayDevice->getWideColorSupport() && !mForceNativeColorMode);
-        mRenderEngine->setColorMode(mForceNativeColorMode ?
+        getBE().mRenderEngine->setColorMode(mForceNativeColorMode ?
                 HAL_COLOR_MODE_NATIVE : displayDevice->getActiveColorMode());
         if (!displayDevice->makeCurrent()) {
             ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
@@ -2685,14 +2690,14 @@
         }
 
         // Never touch the framebuffer if we don't have any framebuffer layers
-        const bool hasDeviceComposition = mHwc->hasDeviceComposition(hwcId);
+        const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(hwcId);
         if (hasDeviceComposition) {
             // when using overlays, we assume a fully transparent framebuffer
             // NOTE: we could reduce how much we need to clear, for instance
             // remove where there are opaque FB layers. however, on some
             // GPUs doing a "clean slate" clear might be more efficient.
             // We'll revisit later if needed.
-            mRenderEngine->clearWithColor(0, 0, 0, 0);
+            getBE().mRenderEngine->clearWithColor(0, 0, 0, 0);
         } else {
             // we start with the whole screen area and remove the scissor part
             // we're left with the letterbox region
@@ -2722,7 +2727,7 @@
 
                 // enable scissor for this frame
                 const uint32_t height = displayDevice->getHeight();
-                mRenderEngine->setScissor(scissor.left, height - scissor.bottom,
+                getBE().mRenderEngine->setScissor(scissor.left, height - scissor.bottom,
                         scissor.getWidth(), scissor.getHeight());
             }
         }
@@ -2787,7 +2792,7 @@
     }
 
     // disable scissor at the end of the frame
-    mRenderEngine->disableScissor();
+    getBE().mRenderEngine->disableScissor();
     return true;
 }
 
@@ -3359,7 +3364,7 @@
     setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL,
                          /*stateLockHeld*/ false);
 
-    const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
     const nsecs_t period = activeConfig->getVsyncPeriod();
     mAnimFrameTracker.setDisplayRefreshPeriod(period);
 
@@ -3612,7 +3617,7 @@
         index++;
     }
 
-    const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
     const nsecs_t period = activeConfig->getVsyncPeriod();
     result.appendFormat("%" PRId64 "\n", period);
 
@@ -3675,24 +3680,24 @@
 void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
 {
     result.appendFormat("Static screen stats:\n");
-    for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) {
-        float bucketTimeSec = mFrameBuckets[b] / 1e9;
+    for (size_t b = 0; b < SurfaceFlingerBE::NUM_BUCKETS - 1; ++b) {
+        float bucketTimeSec = getBE().mFrameBuckets[b] / 1e9;
         float percent = 100.0f *
-                static_cast<float>(mFrameBuckets[b]) / mTotalTime;
+                static_cast<float>(getBE().mFrameBuckets[b]) / getBE().mTotalTime;
         result.appendFormat("  < %zd frames: %.3f s (%.1f%%)\n",
                 b + 1, bucketTimeSec, percent);
     }
-    float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9;
+    float bucketTimeSec = getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1] / 1e9;
     float percent = 100.0f *
-            static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime;
+            static_cast<float>(getBE().mFrameBuckets[SurfaceFlingerBE::NUM_BUCKETS - 1]) / getBE().mTotalTime;
     result.appendFormat("  %zd+ frames: %.3f s (%.1f%%)\n",
-            NUM_BUCKETS - 1, bucketTimeSec, percent);
+            SurfaceFlingerBE::NUM_BUCKETS - 1, bucketTimeSec, percent);
 }
 
 void SurfaceFlinger::recordBufferingStats(const char* layerName,
         std::vector<OccupancyTracker::Segment>&& history) {
-    Mutex::Autolock lock(mBufferingStatsMutex);
-    auto& stats = mBufferingStats[layerName];
+    Mutex::Autolock lock(getBE().mBufferingStatsMutex);
+    auto& stats = getBE().mBufferingStats[layerName];
     for (const auto& segment : history) {
         if (!segment.usedThirdBuffer) {
             stats.twoBufferTime += segment.totalTime;
@@ -3721,12 +3726,12 @@
     result.append("Buffering stats:\n");
     result.append("  [Layer name] <Active time> <Two buffer> "
             "<Double buffered> <Triple buffered>\n");
-    Mutex::Autolock lock(mBufferingStatsMutex);
+    Mutex::Autolock lock(getBE().mBufferingStatsMutex);
     typedef std::tuple<std::string, float, float, float> BufferTuple;
     std::map<float, BufferTuple, std::greater<float>> sorted;
-    for (const auto& statsPair : mBufferingStats) {
+    for (const auto& statsPair : getBE().mBufferingStats) {
         const char* name = statsPair.first.c_str();
-        const BufferingStats& stats = statsPair.second;
+        const SurfaceFlingerBE::BufferingStats& stats = statsPair.second;
         if (stats.numSegments == 0) {
             continue;
         }
@@ -3829,7 +3834,7 @@
     result.append(SyncFeatures::getInstance().toString());
     result.append("\n");
 
-    const auto& activeConfig = mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
 
     colorizer.bold(result);
     result.append("DispSync configuration: ");
@@ -3881,7 +3886,7 @@
     HWComposer& hwc(getHwComposer());
     sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
 
-    mRenderEngine->dump(result);
+    getBE().mRenderEngine->dump(result);
 
     hw->undefinedRegion.dump(result, "undefinedRegion");
     result.appendFormat("  orientation=%d, isDisplayOn=%d\n",
@@ -4533,9 +4538,10 @@
     // dependent on the context's EGLConfig.
     renderScreenImplLocked(renderArea, traverseLayers, true, useIdentityTransform);
 
-    *outSyncFd = getRenderEngine().flush(DEBUG_SCREENSHOTS);
-
     if (DEBUG_SCREENSHOTS) {
+        getRenderEngine().finish();
+        *outSyncFd = -1;
+
         const auto reqWidth = renderArea.getReqWidth();
         const auto reqHeight = renderArea.getReqHeight();
 
@@ -4543,6 +4549,12 @@
         getRenderEngine().readPixels(0, 0, reqWidth, reqHeight, pixels);
         checkScreenshot(reqWidth, reqHeight, reqWidth, pixels, traverseLayers);
         delete [] pixels;
+    } else {
+        base::unique_fd syncFd = getRenderEngine().flush();
+        if (syncFd < 0) {
+            getRenderEngine().finish();
+        }
+        *outSyncFd = syncFd.release();
     }
 
     return NO_ERROR;
@@ -4613,4 +4625,4 @@
 
 #if defined(__gl2_h_)
 #error "don't include gl2/gl2.h in this file"
-#endif
\ No newline at end of file
+#endif
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 974de94..2477bdc 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -92,6 +92,7 @@
 class EventControlThread;
 class VSyncSource;
 class InjectVSyncSource;
+class SurfaceFlingerBE;
 
 typedef std::function<void(const LayerVector::Visitor&)> TraverseLayersFunction;
 
@@ -108,12 +109,97 @@
     eTransactionMask          = 0x07
 };
 
+class SurfaceFlingerBE
+{
+public:
+    SurfaceFlingerBE();
+
+    // The current hardware composer interface.
+    //
+    // The following thread safety rules apply when accessing mHwc, either
+    // directly or via getHwComposer():
+    //
+    // 1. When recreating mHwc, acquire mStateLock. We currently recreate mHwc
+    //    only when switching into and out of vr. Recreating mHwc must only be
+    //    done on the main thread.
+    //
+    // 2. When accessing mHwc on the main thread, it's not necessary to acquire
+    //    mStateLock.
+    //
+    // 3. When accessing mHwc on a thread other than the main thread, we always
+    //    need to acquire mStateLock. This is because the main thread could be
+    //    in the process of destroying the current mHwc instance.
+    //
+    // The above thread safety rules only apply to SurfaceFlinger.cpp. In
+    // SurfaceFlinger_hwc1.cpp we create mHwc at surface flinger init and never
+    // destroy it, so it's always safe to access mHwc from any thread without
+    // acquiring mStateLock.
+    std::unique_ptr<HWComposer> mHwc;
+
+    const std::string mHwcServiceName; // "default" for real use, something else for testing.
+
+    // constant members (no synchronization needed for access)
+    std::unique_ptr<RenderEngine> mRenderEngine;
+    EGLContext mEGLContext;
+    EGLDisplay mEGLDisplay;
+    
+    FenceTimeline mGlCompositionDoneTimeline;
+    FenceTimeline mDisplayTimeline;
+
+    // protected by mCompositorTimingLock;
+    mutable std::mutex mCompositorTimingLock;
+    CompositorTiming mCompositorTiming;
+    
+    // Only accessed from the main thread.
+    struct CompositePresentTime {
+        nsecs_t composite { -1 };
+        std::shared_ptr<FenceTime> display { FenceTime::NO_FENCE };
+    };
+    std::queue<CompositePresentTime> mCompositePresentTimes;
+
+    static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
+    nsecs_t mFrameBuckets[NUM_BUCKETS];
+    nsecs_t mTotalTime;
+    std::atomic<nsecs_t> mLastSwapTime;
+
+    // Double- vs. triple-buffering stats
+    struct BufferingStats {
+        BufferingStats()
+          : numSegments(0),
+            totalTime(0),
+            twoBufferTime(0),
+            doubleBufferedTime(0),
+            tripleBufferedTime(0) {}
+
+        size_t numSegments;
+        nsecs_t totalTime;
+
+        // "Two buffer" means that a third buffer was never used, whereas
+        // "double-buffered" means that on average the segment only used two
+        // buffers (though it may have used a third for some part of the
+        // segment)
+        nsecs_t twoBufferTime;
+        nsecs_t doubleBufferedTime;
+        nsecs_t tripleBufferedTime;
+    };
+    mutable Mutex mBufferingStatsMutex;
+    std::unordered_map<std::string, BufferingStats> mBufferingStats;
+
+    // The composer sequence id is a monotonically increasing integer that we
+    // use to differentiate callbacks from different hardware composer
+    // instances. Each hardware composer instance gets a different sequence id.
+    int32_t mComposerSequenceId;
+};
+
+
 class SurfaceFlinger : public BnSurfaceComposer,
                        public PriorityDumper,
                        private IBinder::DeathRecipient,
                        private HWC2::ComposerCallback
 {
 public:
+    SurfaceFlingerBE& getBE() { return mBE; }
+    const SurfaceFlingerBE& getBE() const { return mBE; }
 
     // This is the phase offset in nanoseconds of the software vsync event
     // relative to the vsync event reported by HWComposer.  The software vsync
@@ -219,7 +305,7 @@
     const Vector< sp<Layer> >& getLayerSortedByZForHwcDisplay(int id);
 
     RenderEngine& getRenderEngine() const {
-        return *mRenderEngine;
+        return *getBE().mRenderEngine;
     }
 
     bool authenticateSurfaceTextureLocked(
@@ -509,7 +595,7 @@
      * H/W composer
      */
 
-    HWComposer& getHwComposer() const { return *mHwc; }
+    HWComposer& getHwComposer() const { return *getBE().mHwc; }
 
     /* ------------------------------------------------------------------------
      * Compositing
@@ -632,32 +718,7 @@
     // access must be protected by mInvalidateLock
     volatile int32_t mRepaintEverything;
 
-    // The current hardware composer interface.
-    //
-    // The following thread safety rules apply when accessing mHwc, either
-    // directly or via getHwComposer():
-    //
-    // 1. When recreating mHwc, acquire mStateLock. We currently recreate mHwc
-    //    only when switching into and out of vr. Recreating mHwc must only be
-    //    done on the main thread.
-    //
-    // 2. When accessing mHwc on the main thread, it's not necessary to acquire
-    //    mStateLock.
-    //
-    // 3. When accessing mHwc on a thread other than the main thread, we always
-    //    need to acquire mStateLock. This is because the main thread could be
-    //    in the process of destroying the current mHwc instance.
-    //
-    // The above thread safety rules only apply to SurfaceFlinger.cpp. In
-    // SurfaceFlinger_hwc1.cpp we create mHwc at surface flinger init and never
-    // destroy it, so it's always safe to access mHwc from any thread without
-    // acquiring mStateLock.
-    std::unique_ptr<HWComposer> mHwc;
-
-    const std::string mHwcServiceName; // "default" for real use, something else for testing.
-
     // constant members (no synchronization needed for access)
-    std::unique_ptr<RenderEngine> mRenderEngine;
     nsecs_t mBootTime;
     bool mGpuToCpuSupported;
     sp<EventThread> mEventThread;
@@ -676,8 +737,6 @@
     std::vector<sp<Layer>> mLayersWithQueuedFrames;
     sp<Fence> mPreviousPresentFence = Fence::NO_FENCE;
     bool mHadClientComposition = false;
-    FenceTimeline mGlCompositionDoneTimeline;
-    FenceTimeline mDisplayTimeline;
 
     // this may only be written from the main thread with mStateLock held
     // it may be read from other threads with mStateLock held
@@ -716,17 +775,6 @@
     bool mPrimaryHWVsyncEnabled;
     bool mHWVsyncAvailable;
 
-    // protected by mCompositorTimingLock;
-    mutable std::mutex mCompositorTimingLock;
-    CompositorTiming mCompositorTiming;
-
-    // Only accessed from the main thread.
-    struct CompositePresentTime {
-        nsecs_t composite { -1 };
-        std::shared_ptr<FenceTime> display { FenceTime::NO_FENCE };
-    };
-    std::queue<CompositePresentTime> mCompositePresentTimes;
-
     std::atomic<bool> mRefreshPending{false};
 
     /* ------------------------------------------------------------------------
@@ -743,35 +791,9 @@
 
     // Static screen stats
     bool mHasPoweredOff;
-    static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
-    nsecs_t mFrameBuckets[NUM_BUCKETS];
-    nsecs_t mTotalTime;
-    std::atomic<nsecs_t> mLastSwapTime;
 
     size_t mNumLayers;
 
-    // Double- vs. triple-buffering stats
-    struct BufferingStats {
-        BufferingStats()
-          : numSegments(0),
-            totalTime(0),
-            twoBufferTime(0),
-            doubleBufferedTime(0),
-            tripleBufferedTime(0) {}
-
-        size_t numSegments;
-        nsecs_t totalTime;
-
-        // "Two buffer" means that a third buffer was never used, whereas
-        // "double-buffered" means that on average the segment only used two
-        // buffers (though it may have used a third for some part of the
-        // segment)
-        nsecs_t twoBufferTime;
-        nsecs_t doubleBufferedTime;
-        nsecs_t tripleBufferedTime;
-    };
-    mutable Mutex mBufferingStatsMutex;
-    std::unordered_map<std::string, BufferingStats> mBufferingStats;
 
     // Verify that transaction is being called by an approved process:
     // either AID_GRAPHICS or AID_SYSTEM.
@@ -781,13 +803,11 @@
     std::atomic<bool> mVrFlingerRequestsDisplay;
     static bool useVrFlinger;
     std::thread::id mMainThreadId;
-    // The composer sequence id is a monotonically increasing integer that we
-    // use to differentiate callbacks from different hardware composer
-    // instances. Each hardware composer instance gets a different sequence id.
-    int32_t mComposerSequenceId;
 
     float mSaturation = 1.0f;
     bool mForceNativeColorMode = false;
+
+    SurfaceFlingerBE mBE;
 };
 }; // namespace android
 
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.cpp b/services/surfaceflinger/SurfaceFlingerConsumer.cpp
deleted file mode 100644
index e17bb58..0000000
--- a/services/surfaceflinger/SurfaceFlingerConsumer.cpp
+++ /dev/null
@@ -1,272 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
-//#define LOG_NDEBUG 0
-
-#include "SurfaceFlingerConsumer.h"
-#include "Layer.h"
-
-#include <private/gui/SyncFeatures.h>
-
-#include <gui/BufferItem.h>
-#include <gui/BufferQueue.h>
-
-#include <utils/Errors.h>
-#include <utils/NativeHandle.h>
-#include <utils/Trace.h>
-
-namespace android {
-
-// ---------------------------------------------------------------------------
-
-status_t SurfaceFlingerConsumer::updateTexImage(BufferRejecter* rejecter,
-        const DispSync& dispSync, bool* autoRefresh, bool* queuedBuffer,
-        uint64_t maxFrameNumber)
-{
-    ATRACE_CALL();
-    ALOGV("updateTexImage");
-    Mutex::Autolock lock(mMutex);
-
-    if (mAbandoned) {
-        ALOGE("updateTexImage: GLConsumer is abandoned!");
-        return NO_INIT;
-    }
-
-    // Make sure the EGL state is the same as in previous calls.
-    status_t err = checkAndUpdateEglStateLocked();
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    BufferItem item;
-
-    // Acquire the next buffer.
-    // In asynchronous mode the list is guaranteed to be one buffer
-    // deep, while in synchronous mode we use the oldest buffer.
-    err = acquireBufferLocked(&item, computeExpectedPresent(dispSync),
-            maxFrameNumber);
-    if (err != NO_ERROR) {
-        if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
-            err = NO_ERROR;
-        } else if (err == BufferQueue::PRESENT_LATER) {
-            // return the error, without logging
-        } else {
-            ALOGE("updateTexImage: acquire failed: %s (%d)",
-                strerror(-err), err);
-        }
-        return err;
-    }
-
-    if (autoRefresh) {
-        *autoRefresh = item.mAutoRefresh;
-    }
-
-    if (queuedBuffer) {
-        *queuedBuffer = item.mQueuedBuffer;
-    }
-
-    // We call the rejecter here, in case the caller has a reason to
-    // not accept this buffer.  This is used by SurfaceFlinger to
-    // reject buffers which have the wrong size
-    int slot = item.mSlot;
-    if (rejecter && rejecter->reject(mSlots[slot].mGraphicBuffer, item)) {
-        releaseBufferLocked(slot, mSlots[slot].mGraphicBuffer, EGL_NO_SYNC_KHR);
-        return BUFFER_REJECTED;
-    }
-
-    // Release the previous buffer.
-    err = updateAndReleaseLocked(item, &mPendingRelease);
-    if (err != NO_ERROR) {
-        return err;
-    }
-
-    if (!SyncFeatures::getInstance().useNativeFenceSync()) {
-        // Bind the new buffer to the GL texture.
-        //
-        // Older devices require the "implicit" synchronization provided
-        // by glEGLImageTargetTexture2DOES, which this method calls.  Newer
-        // devices will either call this in Layer::onDraw, or (if it's not
-        // a GL-composited layer) not at all.
-        err = bindTextureImageLocked();
-    }
-
-    return err;
-}
-
-status_t SurfaceFlingerConsumer::bindTextureImage()
-{
-    Mutex::Autolock lock(mMutex);
-
-    return bindTextureImageLocked();
-}
-
-status_t SurfaceFlingerConsumer::acquireBufferLocked(BufferItem* item,
-        nsecs_t presentWhen, uint64_t maxFrameNumber) {
-    status_t result = GLConsumer::acquireBufferLocked(item, presentWhen,
-            maxFrameNumber);
-    if (result == NO_ERROR) {
-        mTransformToDisplayInverse = item->mTransformToDisplayInverse;
-        mSurfaceDamage = item->mSurfaceDamage;
-    }
-    return result;
-}
-
-bool SurfaceFlingerConsumer::getTransformToDisplayInverse() const {
-    Mutex::Autolock lock(mMutex);
-    return mTransformToDisplayInverse;
-}
-
-const Region& SurfaceFlingerConsumer::getSurfaceDamage() const {
-    return mSurfaceDamage;
-}
-
-sp<NativeHandle> SurfaceFlingerConsumer::getSidebandStream() const {
-    sp<NativeHandle> stream;
-    mConsumer->getSidebandStream(&stream);
-    return stream;
-}
-
-// We need to determine the time when a buffer acquired now will be
-// displayed.  This can be calculated:
-//   time when previous buffer's actual-present fence was signaled
-//    + current display refresh rate * HWC latency
-//    + a little extra padding
-//
-// Buffer producers are expected to set their desired presentation time
-// based on choreographer time stamps, which (coming from vsync events)
-// will be slightly later then the actual-present timing.  If we get a
-// desired-present time that is unintentionally a hair after the next
-// vsync, we'll hold the frame when we really want to display it.  We
-// need to take the offset between actual-present and reported-vsync
-// into account.
-//
-// If the system is configured without a DispSync phase offset for the app,
-// we also want to throw in a bit of padding to avoid edge cases where we
-// just barely miss.  We want to do it here, not in every app.  A major
-// source of trouble is the app's use of the display's ideal refresh time
-// (via Display.getRefreshRate()), which could be off of the actual refresh
-// by a few percent, with the error multiplied by the number of frames
-// between now and when the buffer should be displayed.
-//
-// If the refresh reported to the app has a phase offset, we shouldn't need
-// to tweak anything here.
-nsecs_t SurfaceFlingerConsumer::computeExpectedPresent(const DispSync& dispSync)
-{
-    // The HWC doesn't currently have a way to report additional latency.
-    // Assume that whatever we submit now will appear right after the flip.
-    // For a smart panel this might be 1.  This is expressed in frames,
-    // rather than time, because we expect to have a constant frame delay
-    // regardless of the refresh rate.
-    const uint32_t hwcLatency = 0;
-
-    // Ask DispSync when the next refresh will be (CLOCK_MONOTONIC).
-    const nsecs_t nextRefresh = dispSync.computeNextRefresh(hwcLatency);
-
-    // The DispSync time is already adjusted for the difference between
-    // vsync and reported-vsync (SurfaceFlinger::dispSyncPresentTimeOffset), so
-    // we don't need to factor that in here.  Pad a little to avoid
-    // weird effects if apps might be requesting times right on the edge.
-    nsecs_t extraPadding = 0;
-    if (SurfaceFlinger::vsyncPhaseOffsetNs == 0) {
-        extraPadding = 1000000;        // 1ms (6% of 60Hz)
-    }
-
-    return nextRefresh + extraPadding;
-}
-
-sp<Fence> SurfaceFlingerConsumer::getPrevFinalReleaseFence() const {
-    Mutex::Autolock lock(mMutex);
-    return ConsumerBase::mPrevFinalReleaseFence;
-}
-
-void SurfaceFlingerConsumer::setReleaseFence(const sp<Fence>& fence)
-{
-    if (!mPendingRelease.isPending) {
-        GLConsumer::setReleaseFence(fence);
-        return;
-    }
-    auto currentTexture = mPendingRelease.currentTexture;
-    if (fence->isValid() &&
-            currentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
-        status_t result = addReleaseFence(currentTexture,
-                mPendingRelease.graphicBuffer, fence);
-        ALOGE_IF(result != NO_ERROR, "setReleaseFence: failed to add the"
-                " fence: %s (%d)", strerror(-result), result);
-    }
-}
-
-bool SurfaceFlingerConsumer::releasePendingBuffer()
-{
-    if (!mPendingRelease.isPending) {
-        ALOGV("Pending buffer already released");
-        return false;
-    }
-    ALOGV("Releasing pending buffer");
-    Mutex::Autolock lock(mMutex);
-    status_t result = releaseBufferLocked(mPendingRelease.currentTexture,
-            mPendingRelease.graphicBuffer, mPendingRelease.display,
-            mPendingRelease.fence);
-    ALOGE_IF(result < NO_ERROR, "releasePendingBuffer failed: %s (%d)",
-            strerror(-result), result);
-    mPendingRelease = PendingRelease();
-    return true;
-}
-
-void SurfaceFlingerConsumer::setContentsChangedListener(
-        const wp<ContentsChangedListener>& listener) {
-    setFrameAvailableListener(listener);
-    Mutex::Autolock lock(mMutex);
-    mContentsChangedListener = listener;
-}
-
-void SurfaceFlingerConsumer::onSidebandStreamChanged() {
-    FrameAvailableListener* unsafeFrameAvailableListener = nullptr;
-    {
-        Mutex::Autolock lock(mFrameAvailableMutex);
-        unsafeFrameAvailableListener = mFrameAvailableListener.unsafe_get();
-    }
-    sp<ContentsChangedListener> listener;
-    {   // scope for the lock
-        Mutex::Autolock lock(mMutex);
-        ALOG_ASSERT(unsafeFrameAvailableListener == mContentsChangedListener.unsafe_get());
-        listener = mContentsChangedListener.promote();
-    }
-
-    if (listener != NULL) {
-        listener->onSidebandStreamChanged();
-    }
-}
-
-void SurfaceFlingerConsumer::onDisconnect() {
-    sp<Layer> l = mLayer.promote();
-    if (l.get()) {
-        l->onDisconnect();
-    }
-}
-
-void SurfaceFlingerConsumer::addAndGetFrameTimestamps(
-        const NewFrameEventsEntry* newTimestamps,
-        FrameEventHistoryDelta *outDelta) {
-    sp<Layer> l = mLayer.promote();
-    if (l.get()) {
-        l->addAndGetFrameTimestamps(newTimestamps, outDelta);
-    }
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
diff --git a/services/surfaceflinger/SurfaceFlingerConsumer.h b/services/surfaceflinger/SurfaceFlingerConsumer.h
deleted file mode 100644
index 53b4915..0000000
--- a/services/surfaceflinger/SurfaceFlingerConsumer.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SURFACEFLINGERCONSUMER_H
-#define ANDROID_SURFACEFLINGERCONSUMER_H
-
-#include "DispSync.h"
-
-#include <ui/Region.h>
-#include <gui/GLConsumer.h>
-
-namespace android {
-// ----------------------------------------------------------------------------
-
-class Layer;
-
-/*
- * This is a thin wrapper around GLConsumer.
- */
-class SurfaceFlingerConsumer : public GLConsumer {
-public:
-    static const status_t BUFFER_REJECTED = UNKNOWN_ERROR + 8;
-
-    struct ContentsChangedListener: public FrameAvailableListener {
-        virtual void onSidebandStreamChanged() = 0;
-    };
-
-    SurfaceFlingerConsumer(const sp<IGraphicBufferConsumer>& consumer,
-            uint32_t tex, Layer* layer)
-        : GLConsumer(consumer, tex, GLConsumer::TEXTURE_EXTERNAL, false, false),
-          mTransformToDisplayInverse(false), mSurfaceDamage(), mLayer(layer)
-    {}
-
-    class BufferRejecter {
-        friend class SurfaceFlingerConsumer;
-        virtual bool reject(const sp<GraphicBuffer>& buf,
-                const BufferItem& item) = 0;
-
-    protected:
-        virtual ~BufferRejecter() { }
-    };
-
-    virtual status_t acquireBufferLocked(BufferItem *item, nsecs_t presentWhen,
-            uint64_t maxFrameNumber = 0) override;
-
-    // This version of updateTexImage() takes a functor that may be used to
-    // reject the newly acquired buffer.  Unlike the GLConsumer version,
-    // this does not guarantee that the buffer has been bound to the GL
-    // texture.
-    status_t updateTexImage(BufferRejecter* rejecter, const DispSync& dispSync,
-            bool* autoRefresh, bool* queuedBuffer,
-            uint64_t maxFrameNumber);
-
-    // See GLConsumer::bindTextureImageLocked().
-    status_t bindTextureImage();
-
-    bool getTransformToDisplayInverse() const;
-
-    // must be called from SF main thread
-    const Region& getSurfaceDamage() const;
-
-    // Sets the contents changed listener. This should be used instead of
-    // ConsumerBase::setFrameAvailableListener().
-    void setContentsChangedListener(const wp<ContentsChangedListener>& listener);
-
-    sp<NativeHandle> getSidebandStream() const;
-
-    nsecs_t computeExpectedPresent(const DispSync& dispSync);
-
-    sp<Fence> getPrevFinalReleaseFence() const;
-    virtual void setReleaseFence(const sp<Fence>& fence) override;
-    bool releasePendingBuffer();
-
-    void onDisconnect() override;
-    void addAndGetFrameTimestamps(
-            const NewFrameEventsEntry* newTimestamps,
-            FrameEventHistoryDelta* outDelta) override;
-
-private:
-    virtual void onSidebandStreamChanged();
-
-    wp<ContentsChangedListener> mContentsChangedListener;
-
-    // Indicates this buffer must be transformed by the inverse transform of the screen
-    // it is displayed onto. This is applied after GLConsumer::mCurrentTransform.
-    // This must be set/read from SurfaceFlinger's main thread.
-    bool mTransformToDisplayInverse;
-
-    // The portion of this surface that has changed since the previous frame
-    Region mSurfaceDamage;
-
-    // A release that is pending on the receipt of a new release fence from
-    // presentDisplay
-    PendingRelease mPendingRelease;
-
-    // The layer for this SurfaceFlingerConsumer
-    const wp<Layer> mLayer;
-};
-
-// ----------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_SURFACEFLINGERCONSUMER_H
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index 37925a1..e05ed53 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -224,6 +224,27 @@
     return r;
 }
 
+FloatRect Transform::transform(const FloatRect& bounds) const
+{
+    vec2 lt(bounds.left, bounds.top);
+    vec2 rt(bounds.right, bounds.top);
+    vec2 lb(bounds.left, bounds.bottom);
+    vec2 rb(bounds.right, bounds.bottom);
+
+    lt = transform(lt);
+    rt = transform(rt);
+    lb = transform(lb);
+    rb = transform(rb);
+
+    FloatRect r;
+    r.left = min(lt[0], rt[0], lb[0], rb[0]);
+    r.top = min(lt[1], rt[1], lb[1], rb[1]);
+    r.right = max(lt[0], rt[0], lb[0], rb[0]);
+    r.bottom = max(lt[1], rt[1], lb[1], rb[1]);
+
+    return r;
+}
+
 Region Transform::transform(const Region& reg) const
 {
     Region out;
diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
index bfc66ec..b11d057 100644
--- a/services/surfaceflinger/Transform.h
+++ b/services/surfaceflinger/Transform.h
@@ -84,6 +84,7 @@
             Region  transform(const Region& reg) const;
             Rect    transform(const Rect& bounds,
                     bool roundOutwards = false) const;
+            FloatRect transform(const FloatRect& bounds) const;
             Transform operator * (const Transform& rhs) const;
             // assumes the last row is < 0 , 0 , 1 >
             vec2 transform(const vec2& v) const;
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
index d97ffa3..cb22932 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.cpp
@@ -156,6 +156,10 @@
 
 FakeComposerClient::~FakeComposerClient() {}
 
+bool FakeComposerClient::hasCapability(hwc2_capability_t /*capability*/) {
+    return false;
+}
+
 void FakeComposerClient::removeClient() {
     ALOGV("removeClient");
     // TODO: Ahooga! Only thing current lifetime management choices in
@@ -581,7 +585,7 @@
 }
 
 void FakeComposerClient::onSurfaceFlingerStart() {
-    mSurfaceComposer == nullptr;
+    mSurfaceComposer = nullptr;
     do {
         mSurfaceComposer = new android::SurfaceComposerClient;
         android::status_t initResult = mSurfaceComposer->initCheck();
diff --git a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
index b944182..de8cffd 100644
--- a/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
+++ b/services/surfaceflinger/tests/fakehwc/FakeComposerClient.h
@@ -59,6 +59,8 @@
     FakeComposerClient();
     virtual ~FakeComposerClient();
 
+    bool hasCapability(hwc2_capability_t capability) override;
+
     void removeClient() override;
     void enableCallback(bool enable) override;
     uint32_t getMaxVirtualDisplayCount() override;
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 7f4c58a..8a97ea4 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -165,7 +165,7 @@
     sp<ComposerClient> client = new ComposerClient(*mMockComposer);
     mMockComposer->setClient(client.get());
     mFakeService = new FakeComposerService(client);
-    mFakeService->registerAsService("mock");
+    (void)mFakeService->registerAsService("mock");
 
     android::hardware::ProcessState::self()->startThreadPool();
     android::ProcessState::self()->startThreadPool();
@@ -323,7 +323,7 @@
     sp<ComposerClient> client = new ComposerClient(*sFakeComposer);
     sFakeComposer->setClient(client.get());
     sp<IComposer> fakeService = new FakeComposerService(client);
-    fakeService->registerAsService("mock");
+    (void)fakeService->registerAsService("mock");
 
     android::hardware::ProcessState::self()->startThreadPool();
     android::ProcessState::self()->startThreadPool();
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index fd271d0..d5664d5 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -232,7 +232,7 @@
 
 VrHwc::~VrHwc() {}
 
-bool VrHwc::hasCapability(Capability /* capability */) const { return false; }
+bool VrHwc::hasCapability(hwc2_capability_t /* capability */) { return false; }
 
 void VrHwc::removeClient() {
   std::lock_guard<std::mutex> guard(mutex_);
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index fce9a06..eff721b 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -196,8 +196,6 @@
   VrHwc();
   ~VrHwc() override;
 
-  bool hasCapability(Capability capability) const;
-
   Error setLayerInfo(Display display, Layer layer, uint32_t type,
                      uint32_t appId);
   Error setClientTargetMetadata(
@@ -207,6 +205,8 @@
       const IVrComposerClient::BufferMetadata& metadata);
 
   // ComposerBase
+  bool hasCapability(hwc2_capability_t capability) override;
+
   void removeClient() override;
   void enableCallback(bool enable) override;