Merge "[GraphicsEnvironment] Add clang-format on GraphicsEnvironment"
diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp
index 28c7658..b2e7047 100644
--- a/cmds/installd/otapreopt.cpp
+++ b/cmds/installd/otapreopt.cpp
@@ -322,21 +322,8 @@
             return false;
         }
         const char* isa = parameters_.instruction_set;
-
-        // Check whether the file exists where expected.
         std::string dalvik_cache = GetOTADataDirectory() + "/" + DALVIK_CACHE;
         std::string isa_path = dalvik_cache + "/" + isa;
-        std::string art_path = isa_path + "/system@framework@boot.art";
-        std::string oat_path = isa_path + "/system@framework@boot.oat";
-        bool cleared = false;
-        if (access(art_path.c_str(), F_OK) == 0 && access(oat_path.c_str(), F_OK) == 0) {
-            // Files exist, assume everything is alright if not forced. Otherwise clean up.
-            if (!force) {
-                return true;
-            }
-            ClearDirectory(isa_path);
-            cleared = true;
-        }
 
         // Reset umask in otapreopt, so that we control the the access for the files we create.
         umask(0);
@@ -355,17 +342,34 @@
             }
         }
 
-        // Prepare to create.
+        // Check whether we have files in /data.
+        // TODO: check that the files are correct wrt/ jars.
+        std::string art_path = isa_path + "/system@framework@boot.art";
+        std::string oat_path = isa_path + "/system@framework@boot.oat";
+        bool cleared = false;
+        if (access(art_path.c_str(), F_OK) == 0 && access(oat_path.c_str(), F_OK) == 0) {
+            // Files exist, assume everything is alright if not forced. Otherwise clean up.
+            if (!force) {
+                return true;
+            }
+            ClearDirectory(isa_path);
+            cleared = true;
+        }
+
+        // Check whether we have an image in /system.
+        // TODO: check that the files are correct wrt/ jars.
+        std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
+        if (access(preopted_boot_art_path.c_str(), F_OK) == 0) {
+            // Note: we ignore |force| here.
+            return true;
+        }
+
+
         if (!cleared) {
             ClearDirectory(isa_path);
         }
 
-        std::string preopted_boot_art_path = StringPrintf("/system/framework/%s/boot.art", isa);
-        if (access(preopted_boot_art_path.c_str(), F_OK) != 0) {
-          // No preopted boot image. Try to compile.
-          return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa);
-        }
-        return true;
+        return Dex2oatBootImage(boot_classpath_, art_path, oat_path, isa);
     }
 
     static bool CreatePath(const std::string& path) {
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index d776682..79cd6b5 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -274,6 +274,7 @@
     // Note that we ignore the strict_policy and don't propagate it
     // further (since we do no outbound RPCs anyway).
     strict_policy = bio_get_uint32(msg);
+    bio_get_uint32(msg);  // Ignore worksource header.
     s = bio_get_string16(msg, &len);
     if (s == NULL) {
         return -1;
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index f052bcb..7a47724 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -109,6 +109,10 @@
     "BC_DEAD_BINDER_DONE"
 };
 
+// The work source represents the UID of the process we should attribute the transaction to.
+// We use -1 to specify that the work source was not set using #setWorkSource.
+static const int kUnsetWorkSource = -1;
+
 static const char* getReturnString(uint32_t cmd)
 {
     size_t idx = cmd & 0xff;
@@ -383,6 +387,25 @@
     return mStrictModePolicy;
 }
 
+uid_t IPCThreadState::setWorkSource(uid_t uid)
+{
+    uid_t returnValue = mWorkSource;
+    mWorkSource = uid;
+    return returnValue;
+}
+
+uid_t IPCThreadState::getWorkSource() const
+{
+    return mWorkSource;
+}
+
+uid_t IPCThreadState::clearWorkSource()
+{
+    uid_t returnValue = mWorkSource;
+    mWorkSource = kUnsetWorkSource;
+    return returnValue;
+}
+
 void IPCThreadState::setLastTransactionBinderFlags(int32_t flags)
 {
     mLastTransactionBinderFlags = flags;
@@ -736,6 +759,7 @@
 
 IPCThreadState::IPCThreadState()
     : mProcess(ProcessState::self()),
+      mWorkSource(kUnsetWorkSource),
       mStrictModePolicy(0),
       mLastTransactionBinderFlags(0)
 {
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 87c9842..bc1a71c 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -601,6 +601,7 @@
 {
     writeInt32(IPCThreadState::self()->getStrictModePolicy() |
                STRICT_MODE_PENALTY_GATHER);
+    writeInt32(IPCThreadState::self()->getWorkSource());
     // currently the interface identification token is just its name as a string
     return writeString16(interface);
 }
@@ -613,6 +614,7 @@
 bool Parcel::enforceInterface(const String16& interface,
                               IPCThreadState* threadState) const
 {
+    // StrictModePolicy.
     int32_t strictPolicy = readInt32();
     if (threadState == nullptr) {
         threadState = IPCThreadState::self();
@@ -627,6 +629,10 @@
     } else {
       threadState->setStrictModePolicy(strictPolicy);
     }
+    // WorkSource.
+    int32_t workSource = readInt32();
+    threadState->setWorkSource(workSource);
+    // Interface descriptor.
     const String16 str(readString16());
     if (str == interface) {
         return true;
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index 40b51ad..5888e14 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -47,6 +47,13 @@
             void                setStrictModePolicy(int32_t policy);
             int32_t             getStrictModePolicy() const;
 
+            // See Binder#setThreadWorkSource in Binder.java.
+            uid_t               setWorkSource(uid_t uid);
+            // See Binder#getThreadWorkSource in Binder.java.
+            uid_t               getWorkSource() const;
+            // See Binder#clearThreadWorkSource in Binder.java.
+            uid_t               clearWorkSource();
+
             void                setLastTransactionBinderFlags(int32_t flags);
             int32_t             getLastTransactionBinderFlags() const;
 
@@ -155,6 +162,9 @@
             status_t            mLastError;
             pid_t               mCallingPid;
             uid_t               mCallingUid;
+            // The UID of the process who is responsible for this transaction.
+            // This is used for resource attribution.
+            int32_t             mWorkSource;
             int32_t             mStrictModePolicy;
             int32_t             mLastTransactionBinderFlags;
             IPCThreadStateBase  *mIPCThreadStateBase;
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 73c2eba..7bcfffd 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -71,6 +71,7 @@
     BINDER_LIB_TEST_DELAYED_EXIT_TRANSACTION,
     BINDER_LIB_TEST_GET_PTR_SIZE_TRANSACTION,
     BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION,
+    BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION,
 };
 
 pid_t start_server_process(int arg2, bool usePoll = false)
@@ -938,6 +939,43 @@
     EXPECT_EQ(NO_ERROR, ret);
 }
 
+TEST_F(BinderLibTest, WorkSourceUnsetByDefault)
+{
+    status_t ret;
+    Parcel data, reply;
+    data.writeInterfaceToken(binderLibTestServiceName);
+    ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+    EXPECT_EQ(-1, reply.readInt32());
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
+TEST_F(BinderLibTest, WorkSourceSet)
+{
+    status_t ret;
+    Parcel data, reply;
+    uid_t previousWorkSource = IPCThreadState::self()->setWorkSource(100);
+    data.writeInterfaceToken(binderLibTestServiceName);
+    ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+    EXPECT_EQ(100, reply.readInt32());
+    EXPECT_EQ(-1, previousWorkSource);
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
+TEST_F(BinderLibTest, WorkSourceCleared)
+{
+    status_t ret;
+    Parcel data, reply;
+
+    IPCThreadState::self()->setWorkSource(100);
+    uid_t previousWorkSource = IPCThreadState::self()->clearWorkSource();
+    data.writeInterfaceToken(binderLibTestServiceName);
+    ret = m_server->transact(BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION, data, &reply);
+
+    EXPECT_EQ(-1, reply.readInt32());
+    EXPECT_EQ(100, previousWorkSource);
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
 class BinderLibTestService : public BBinder
 {
     public:
@@ -1236,6 +1274,11 @@
                 }
                 return NO_ERROR;
             }
+            case BINDER_LIB_TEST_GET_WORK_SOURCE_TRANSACTION: {
+                data.enforceInterface(binderLibTestServiceName);
+                reply->writeInt32(IPCThreadState::self()->getWorkSource());
+                return NO_ERROR;
+            }
             default:
                 return UNKNOWN_TRANSACTION;
             };
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index e53f7fd..024d72b 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -167,7 +167,7 @@
         auto sphalNamespace = android_get_exported_namespace("sphal");
         if (!sphalNamespace) return;
         mDriverNamespace = android_create_namespace("gfx driver",
-                                                    nullptr,             // ld_library_path
+                                                    mDriverPath.c_str(), // ld_library_path
                                                     mDriverPath.c_str(), // default_library_path
                                                     ANDROID_NAMESPACE_TYPE_SHARED |
                                                             ANDROID_NAMESPACE_TYPE_ISOLATED,
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index 7b35409..0a0c8ca 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -78,7 +78,7 @@
 
     shared_libs: [
         "android.hardware.graphics.allocator@2.0",
-        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.mapper@2.0",
         "android.hardware.graphics.mapper@2.1",
         "android.hardware.configstore@1.0",
@@ -97,7 +97,7 @@
     ],
 
     export_shared_lib_headers: [
-        "android.hardware.graphics.common@1.1",
+        "android.hardware.graphics.common@1.2",
     ],
 
     static_libs: [
diff --git a/libs/ui/DebugUtils.cpp b/libs/ui/DebugUtils.cpp
index 61df02d..ee06d93 100644
--- a/libs/ui/DebugUtils.cpp
+++ b/libs/ui/DebugUtils.cpp
@@ -234,6 +234,9 @@
         case ColorMode::BT2020:
             return std::string("ColorMode::BT2020");
 
+        case ColorMode::DISPLAY_BT2020:
+            return std::string("ColorMode::DISPLAY_BT2020");
+
         case ColorMode::BT2100_PQ:
             return std::string("ColorMode::BT2100_PQ");
 
diff --git a/libs/ui/include/ui/GraphicTypes.h b/libs/ui/include/ui/GraphicTypes.h
index 0fa819d..1d53ac8 100644
--- a/libs/ui/include/ui/GraphicTypes.h
+++ b/libs/ui/include/ui/GraphicTypes.h
@@ -17,6 +17,7 @@
 #pragma once
 
 #include <android/hardware/graphics/common/1.1/types.h>
+#include <android/hardware/graphics/common/1.2/types.h>
 #include <system/graphics.h>
 
 // android::ui::* in this header file will alias different types as
@@ -25,10 +26,10 @@
 namespace ui {
 
 using android::hardware::graphics::common::V1_0::Hdr;
-using android::hardware::graphics::common::V1_1::ColorMode;
-using android::hardware::graphics::common::V1_1::Dataspace;
 using android::hardware::graphics::common::V1_1::PixelFormat;
 using android::hardware::graphics::common::V1_1::RenderIntent;
+using android::hardware::graphics::common::V1_2::ColorMode;
+using android::hardware::graphics::common::V1_2::Dataspace;
 
 }  // namespace ui
 }  // namespace android
diff --git a/libs/vr/libbufferhub/Android.bp b/libs/vr/libbufferhub/Android.bp
index ba5cfcd..43ac79e 100644
--- a/libs/vr/libbufferhub/Android.bp
+++ b/libs/vr/libbufferhub/Android.bp
@@ -22,6 +22,7 @@
     "buffer_hub_base.cpp",
     "buffer_hub_rpc.cpp",
     "consumer_buffer.cpp",
+    "buffer_client_impl.cpp",
     "ion_buffer.cpp",
     "producer_buffer.cpp",
 ]
diff --git a/libs/vr/libbufferhub/buffer_client_impl.cpp b/libs/vr/libbufferhub/buffer_client_impl.cpp
new file mode 100644
index 0000000..6bef98a
--- /dev/null
+++ b/libs/vr/libbufferhub/buffer_client_impl.cpp
@@ -0,0 +1,55 @@
+#include <log/log.h>
+#include <private/dvr/IBufferClient.h>
+
+namespace android {
+namespace dvr {
+
+class BpBufferClient : public BpInterface<IBufferClient> {
+ public:
+  explicit BpBufferClient(const sp<IBinder>& impl)
+      : BpInterface<IBufferClient>(impl) {}
+
+  bool isValid() override;
+};
+
+IMPLEMENT_META_INTERFACE(BufferClient, "android.dvr.IBufferClient");
+
+// Transaction code
+enum {
+  IS_VALID = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+bool BpBufferClient::isValid() {
+  Parcel data, reply;
+  status_t ret =
+      data.writeInterfaceToken(IBufferClient::getInterfaceDescriptor());
+  if (ret != NO_ERROR) {
+    ALOGE("BpBufferClient::isValid: failed to write into parcel; errno=%d",
+          ret);
+    return false;
+  }
+
+  ret = remote()->transact(IS_VALID, data, &reply);
+  if (ret == NO_ERROR) {
+    return reply.readBool();
+  } else {
+    ALOGE("BpBufferClient::isValid: failed to transact; errno=%d", ret);
+    return false;
+  }
+}
+
+status_t BnBufferClient::onTransact(uint32_t code, const Parcel& data,
+                                    Parcel* reply, uint32_t flags) {
+  switch (code) {
+    case IS_VALID: {
+      CHECK_INTERFACE(IBufferClient, data, reply);
+      return reply->writeBool(isValid());
+    } break;
+    default:
+      // Should not reach except binder defined transactions such as dumpsys
+      return BBinder::onTransact(code, data, reply, flags);
+  }
+}
+
+}  // namespace dvr
+}  // namespace android
\ No newline at end of file
diff --git a/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
new file mode 100644
index 0000000..03f2d95
--- /dev/null
+++ b/libs/vr/libbufferhub/include/private/dvr/IBufferClient.h
@@ -0,0 +1,29 @@
+#ifndef ANDROID_DVR_IBUFFERCLIENT_H
+#define ANDROID_DVR_IBUFFERCLIENT_H
+
+#include <binder/IInterface.h>
+#include <binder/Parcel.h>
+
+namespace android {
+namespace dvr {
+
+// Interface for acessing BufferHubBuffer remotely.
+class IBufferClient : public IInterface {
+ public:
+  DECLARE_META_INTERFACE(BufferClient);
+
+  // Checks if the buffer node is valid.
+  virtual bool isValid() = 0;
+};
+
+// BnInterface for IBufferClient. Should only be created in bufferhub service.
+class BnBufferClient : public BnInterface<IBufferClient> {
+ public:
+  virtual status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply,
+                              uint32_t flags = 0);
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_IBUFFERCLIENT_H
\ No newline at end of file
diff --git a/opengl/libagl/state.cpp b/opengl/libagl/state.cpp
index 1d5def5..8bb7e83 100644
--- a/opengl/libagl/state.cpp
+++ b/opengl/libagl/state.cpp
@@ -181,7 +181,7 @@
     case GL_FOG:
     case GL_DEPTH_TEST:
         ogles_invalidate_perspective(c);
-        // fall-through...
+        [[fallthrough]];
     case GL_BLEND:
     case GL_SCISSOR_TEST:
     case GL_ALPHA_TEST:
diff --git a/opengl/libagl/texture.cpp b/opengl/libagl/texture.cpp
index aae8e05..4c5f3e9 100644
--- a/opengl/libagl/texture.cpp
+++ b/opengl/libagl/texture.cpp
@@ -401,14 +401,14 @@
     switch (format) {
     case GL_PALETTE4_RGB8_OES:
         indexBits = 4;
-        /* FALLTHROUGH */
+        [[fallthrough]];
     case GL_PALETTE8_RGB8_OES:
         entrySize = 3;
         break;
 
     case GL_PALETTE4_RGBA8_OES:
         indexBits = 4;
-        /* FALLTHROUGH */
+        [[fallthrough]];
     case GL_PALETTE8_RGBA8_OES:
         entrySize = 4;
         break;
@@ -417,7 +417,7 @@
     case GL_PALETTE4_RGBA4_OES:
     case GL_PALETTE4_RGB5_A1_OES:
         indexBits = 4;
-        /* FALLTHROUGH */
+        [[fallthrough]];
     case GL_PALETTE8_R5_G6_B5_OES:
     case GL_PALETTE8_RGBA4_OES:
     case GL_PALETTE8_RGB5_A1_OES:
@@ -446,14 +446,14 @@
     switch (format) {
     case GL_PALETTE4_RGB8_OES:
         indexBits = 4;
-        /* FALLTHROUGH */
+        [[fallthrough]];
     case GL_PALETTE8_RGB8_OES:
         entrySize = 3;
         break;
 
     case GL_PALETTE4_RGBA8_OES:
         indexBits = 4;
-        /* FALLTHROUGH */
+        [[fallthrough]];
     case GL_PALETTE8_RGBA8_OES:
         entrySize = 4;
         break;
@@ -462,7 +462,7 @@
     case GL_PALETTE4_RGBA4_OES:
     case GL_PALETTE4_RGB5_A1_OES:
         indexBits = 4;
-        /* FALLTHROUGH */
+        [[fallthrough]];
     case GL_PALETTE8_R5_G6_B5_OES:
     case GL_PALETTE8_RGBA4_OES:
     case GL_PALETTE8_RGB5_A1_OES:
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index bff08d0..29a966d 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -437,13 +437,6 @@
     return cnx->platform.eglDestroySyncKHR(dpy, sync);
 }
 
-EGLBoolean eglSignalSync(EGLDisplay dpy, EGLSync sync, EGLenum mode) {
-    clearError();
-
-    egl_connection_t* const cnx = &gEGLImpl;
-    return cnx->platform.eglSignalSync(dpy, sync, mode);
-}
-
 EGLBoolean eglSignalSyncKHR(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) {
     clearError();
 
diff --git a/opengl/libs/EGL/egl_entries.in b/opengl/libs/EGL/egl_entries.in
index 10c305e..2921d51 100644
--- a/opengl/libs/EGL/egl_entries.in
+++ b/opengl/libs/EGL/egl_entries.in
@@ -53,7 +53,6 @@
 EGL_ENTRY(EGLSyncKHR, eglCreateSync, EGLDisplay, EGLenum, const EGLAttrib *)
 EGL_ENTRY(EGLBoolean, eglDestroySync, EGLDisplay, EGLSync)
 EGL_ENTRY(EGLint, eglClientWaitSync, EGLDisplay, EGLSync, EGLint, EGLTimeKHR)
-EGL_ENTRY(EGLBoolean, eglSignalSync, EGLDisplay, EGLSync, EGLenum)
 EGL_ENTRY(EGLBoolean, eglGetSyncAttrib, EGLDisplay, EGLSync, EGLint, EGLAttrib *)
 EGL_ENTRY(EGLBoolean, eglWaitSync, EGLDisplay, EGLSync, EGLint)
 
diff --git a/opengl/libs/EGL/egl_platform_entries.cpp b/opengl/libs/EGL/egl_platform_entries.cpp
index 94c7fdd..1daa4d2 100644
--- a/opengl/libs/EGL/egl_platform_entries.cpp
+++ b/opengl/libs/EGL/egl_platform_entries.cpp
@@ -1861,36 +1861,18 @@
     return eglDestroySyncTmpl(dpy, sync, cnx->egl.eglDestroySyncKHR);
 }
 
-EGLBoolean eglSignalSyncTmpl(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode,
-                             PFNEGLSIGNALSYNCKHRPROC eglSignalSyncFunc) {
+EGLBoolean eglSignalSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) {
     const egl_display_ptr dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
     EGLBoolean result = EGL_FALSE;
     egl_connection_t* const cnx = &gEGLImpl;
-    if (cnx->dso && eglSignalSyncFunc) {
-        result = eglSignalSyncFunc(dp->disp.dpy, sync, mode);
+    if (cnx->dso && gEGLImpl.egl.eglSignalSyncKHR) {
+        result = gEGLImpl.egl.eglSignalSyncKHR(dp->disp.dpy, sync, mode);
     }
     return result;
 }
 
-EGLBoolean eglSignalSyncKHRImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) {
-    return eglSignalSyncTmpl(dpy, sync, mode, gEGLImpl.egl.eglSignalSyncKHR);
-}
-
-EGLBoolean eglSignalSyncImpl(EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode) {
-    egl_connection_t* const cnx = &gEGLImpl;
-    if (cnx->driverVersion >= EGL_MAKE_VERSION(1, 5, 0)) {
-        if (cnx->egl.eglSignalSync) {
-            return eglSignalSyncTmpl(dpy, sync, mode, cnx->egl.eglSignalSync);
-        }
-        ALOGE("Driver indicates EGL 1.5 support, but does not have eglSignalSync");
-        return setError(EGL_BAD_DISPLAY, EGL_FALSE);
-    }
-
-    return eglSignalSyncTmpl(dpy, sync, mode, gEGLImpl.egl.eglSignalSyncKHR);
-}
-
 EGLint eglClientWaitSyncTmpl(EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout,
                              PFNEGLCLIENTWAITSYNCKHRPROC eglClientWaitSyncFunc) {
     const egl_display_ptr dp = validate_display(dpy);
@@ -2668,7 +2650,6 @@
     { "eglDestroyImage", (EGLFuncPointer)&eglDestroyImageImpl },
     { "eglCreateSync", (EGLFuncPointer)&eglCreateSyncImpl },
     { "eglDestroySync", (EGLFuncPointer)&eglDestroySyncImpl },
-    { "eglSignalSync", (EGLFuncPointer)&eglSignalSyncImpl },
     { "eglClientWaitSync", (EGLFuncPointer)&eglClientWaitSyncImpl },
     { "eglGetSyncAttrib", (EGLFuncPointer)&eglGetSyncAttribImpl },
     { "eglCreateSyncKHR", (EGLFuncPointer)&eglCreateSyncKHRImpl },
diff --git a/opengl/libs/platform_entries.in b/opengl/libs/platform_entries.in
index 08f574e..4673411 100644
--- a/opengl/libs/platform_entries.in
+++ b/opengl/libs/platform_entries.in
@@ -46,7 +46,6 @@
 EGL_ENTRY(EGLBoolean, eglDestroyImageKHR, EGLDisplay, EGLImageKHR)
 EGL_ENTRY(EGLSync, eglCreateSync, EGLDisplay, EGLenum, const EGLAttrib*)
 EGL_ENTRY(EGLBoolean, eglDestroySync, EGLDisplay, EGLSync)
-EGL_ENTRY(EGLBoolean, eglSignalSync, EGLDisplay, EGLSync, EGLenum)
 EGL_ENTRY(EGLint, eglClientWaitSync, EGLDisplay, EGLSync, EGLint, EGLTimeKHR)
 EGL_ENTRY(EGLBoolean, eglGetSyncAttrib, EGLDisplay, EGLSyncKHR, EGLint, EGLAttrib*)
 EGL_ENTRY(EGLSyncKHR, eglCreateSyncKHR, EGLDisplay, EGLenum, const EGLint*)
diff --git a/opengl/tools/glgen/specs/egl/EGL15.spec b/opengl/tools/glgen/specs/egl/EGL15.spec
index 8284771..e0aad30 100644
--- a/opengl/tools/glgen/specs/egl/EGL15.spec
+++ b/opengl/tools/glgen/specs/egl/EGL15.spec
@@ -10,3 +10,5 @@
 EGLSurface eglCreatePlatformWindowSurface ( EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list )
 EGLSurface eglCreatePlatformPixmapSurface ( EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list )
 EGLBoolean eglWaitSync ( EGLDisplay dpy, EGLSync sync, EGLint flags )
+EGLImage eglCreateImage ( EGLDisplay dpy, EGLContext context, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list )
+EGLBoolean eglDestroyImage ( EGLDisplay dpy, EGLImage image )
diff --git a/opengl/tools/glgen/specs/egl/checks.spec b/opengl/tools/glgen/specs/egl/checks.spec
index ae531ee..e2bae48 100644
--- a/opengl/tools/glgen/specs/egl/checks.spec
+++ b/opengl/tools/glgen/specs/egl/checks.spec
@@ -11,3 +11,5 @@
 //STUB function: eglCreatePbufferFromClientBuffer nullAllowed attrib_list sentinel attrib_list EGL_NONE
 eglCreateContext sentinel attrib_list EGL_NONE
 eglQueryContext check value 1
+//unsupported: eglCreatePlatformPixmapSurface nullAllowed attrib_list sentinel attrib_list EGL_NONE
+eglCreatePlatformPixmapSurface unsupported
diff --git a/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
new file mode 100644
index 0000000..fd44498
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.cpp
@@ -0,0 +1,46 @@
+/* EGLDisplay eglGetPlatformDisplay ( EGLenum platform, EGLAttrib native_display, const EGLAttrib *attrib_list ) */
+static jobject
+android_eglGetPlatformDisplay
+  (JNIEnv *_env, jobject _this, jint platform, jlong native_display, jlongArray attrib_list_ref, jint offset) {
+    jint _exception = 0;
+    const char * _exceptionType = NULL;
+    const char * _exceptionMessage = NULL;
+    EGLDisplay _returnValue = (EGLDisplay) 0;
+    EGLAttrib *attrib_list_base = (EGLAttrib *) 0;
+    jint _remaining;
+    EGLAttrib *attrib_list = (EGLAttrib *) 0;
+
+    if (!attrib_list_ref) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "attrib_list == null";
+        goto exit;
+    }
+    if (offset < 0) {
+        _exception = 1;
+        _exceptionType = "java/lang/IllegalArgumentException";
+        _exceptionMessage = "offset < 0";
+        goto exit;
+    }
+    _remaining = _env->GetArrayLength(attrib_list_ref) - offset;
+    attrib_list_base = (EGLAttrib *)
+        _env->GetLongArrayElements(attrib_list_ref, (jboolean *)0);
+    attrib_list = attrib_list_base + offset;
+
+    _returnValue = eglGetPlatformDisplay(
+        (EGLenum)platform,
+        (void *)native_display,
+        (EGLAttrib *)attrib_list
+    );
+
+exit:
+    if (attrib_list_base) {
+        _env->ReleaseLongArrayElements(attrib_list_ref, (jlong*)attrib_list_base,
+            JNI_ABORT);
+    }
+    if (_exception) {
+        jniThrowException(_env, _exceptionType, _exceptionMessage);
+    }
+    return toEGLHandle(_env, egldisplayClass, egldisplayConstructor, _returnValue);
+}
+
diff --git a/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.java b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.java
new file mode 100644
index 0000000..28945e8
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.java
@@ -0,0 +1,9 @@
+    // C function EGLDisplay eglGetPlatformDisplay ( EGLenum platform, EGLAttrib native_display, const EGLAttrib *attrib_list )
+
+    public static native EGLDisplay eglGetPlatformDisplay(
+        int platform,
+        long native_display,
+        long[] attrib_list,
+        int offset
+    );
+
diff --git a/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.nativeReg b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.nativeReg
new file mode 100644
index 0000000..8a309bf
--- /dev/null
+++ b/opengl/tools/glgen/stubs/egl/eglGetPlatformDisplay.nativeReg
@@ -0,0 +1 @@
+{"eglGetPlatformDisplay", "(IJ[JI)Landroid/opengl/EGLDisplay;", (void *) android_eglGetPlatformDisplay },
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 9a65452..622a623 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -41,6 +41,8 @@
         "-Wall",
         "-Wextra",
         "-Werror",
+        // Allow implicit fallthroughs in InputReader.cpp until they are fixed.
+        "-Wno-error=implicit-fallthrough",
         "-Wno-unused-parameter",
         // TODO: Move inputflinger to its own process and mark it hidden
         //-fvisibility=hidden
diff --git a/services/sensorservice/RecentEventLogger.cpp b/services/sensorservice/RecentEventLogger.cpp
index cec2ae5..207b097 100644
--- a/services/sensorservice/RecentEventLogger.cpp
+++ b/services/sensorservice/RecentEventLogger.cpp
@@ -32,19 +32,26 @@
 
 RecentEventLogger::RecentEventLogger(int sensorType) :
         mSensorType(sensorType), mEventSize(eventSizeBySensorType(mSensorType)),
-        mRecentEvents(logSizeBySensorType(sensorType)), mMaskData(false) {
+        mRecentEvents(logSizeBySensorType(sensorType)), mMaskData(false),
+        mIsLastEventCurrent(false) {
     // blank
 }
 
 void RecentEventLogger::addEvent(const sensors_event_t& event) {
     std::lock_guard<std::mutex> lk(mLock);
     mRecentEvents.emplace(event);
+    mIsLastEventCurrent = true;
 }
 
 bool RecentEventLogger::isEmpty() const {
     return mRecentEvents.size() == 0;
 }
 
+void RecentEventLogger::setLastEventStale() {
+    std::lock_guard<std::mutex> lk(mLock);
+    mIsLastEventCurrent = false;
+}
+
 std::string RecentEventLogger::dump() const {
     std::lock_guard<std::mutex> lk(mLock);
 
@@ -85,10 +92,10 @@
     }
 }
 
-bool RecentEventLogger::populateLastEvent(sensors_event_t *event) const {
+bool RecentEventLogger::populateLastEventIfCurrent(sensors_event_t *event) const {
     std::lock_guard<std::mutex> lk(mLock);
 
-    if (mRecentEvents.size()) {
+    if (mIsLastEventCurrent && mRecentEvents.size()) {
         // Index 0 contains the latest event emplace()'ed
         *event = mRecentEvents[0].mEvent;
         return true;
diff --git a/services/sensorservice/RecentEventLogger.h b/services/sensorservice/RecentEventLogger.h
index bf1f655..67378b7 100644
--- a/services/sensorservice/RecentEventLogger.h
+++ b/services/sensorservice/RecentEventLogger.h
@@ -37,8 +37,13 @@
 public:
     explicit RecentEventLogger(int sensorType);
     void addEvent(const sensors_event_t& event);
-    bool populateLastEvent(sensors_event_t *event) const;
+
+    // Populate event with the last recorded sensor event if it is not stale. An event is
+    // considered stale if the sensor has become deactivated since the event was recorded.
+    // returns true on success, false if no recent event is available or the last event is stale
+    bool populateLastEventIfCurrent(sensors_event_t *event) const;
     bool isEmpty() const;
+    void setLastEventStale();
     virtual ~RecentEventLogger() {}
 
     // Dumpable interface
@@ -59,6 +64,7 @@
     RingBuffer<SensorEventLog> mRecentEvents;
 
     bool mMaskData;
+    bool mIsLastEventCurrent;
 
 private:
     static size_t logSizeBySensorType(int sensorType);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 1b9b945..85450f8 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -1290,6 +1290,15 @@
             ALOGD_IF(DEBUG_CONNECTIONS, "... and it was the last connection");
             mActiveSensors.removeItemsAt(i, 1);
             mActiveVirtualSensors.erase(handle);
+
+            // If this is the last connection, then mark the RecentEventLogger as stale. This is
+            // critical for on-change events since the previous event is sent to a client if the
+            // sensor is already active. If two clients request the sensor at the same time, one
+            // of the clients would receive a stale event.
+            auto logger = mRecentEvent.find(handle);
+            if (logger != mRecentEvent.end()) {
+                logger->second->setLastEventStale();
+            }
             delete rec;
             size--;
         } else {
@@ -1356,10 +1365,11 @@
                 auto logger = mRecentEvent.find(handle);
                 if (logger != mRecentEvent.end()) {
                     sensors_event_t event;
-                    // It is unlikely that this buffer is empty as the sensor is already active.
-                    // One possible corner case may be two applications activating an on-change
-                    // sensor at the same time.
-                    if(logger->second->populateLastEvent(&event)) {
+                    // Verify that the last sensor event was generated from the current activation
+                    // of the sensor. If not, it is possible for an on-change sensor to receive a
+                    // sensor event that is stale if two clients re-activate the sensor
+                    // simultaneously.
+                    if(logger->second->populateLastEventIfCurrent(&event)) {
                         event.sensor = handle;
                         if (event.version == sizeof(sensors_event_t)) {
                             if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) {
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 339f83b..16003a2 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -30,6 +30,7 @@
         "android.hardware.configstore@1.1",
         "android.hardware.configstore@1.2",
         "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3",
@@ -79,6 +80,7 @@
     ],
     export_shared_lib_headers: [
         "android.hardware.graphics.allocator@2.0",
+        "android.hardware.graphics.common@1.2",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
         "android.hardware.graphics.composer@2.3",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index cafe26b..440f1e2 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -70,6 +70,8 @@
               mName.string());
         destroyAllHwcLayers();
     }
+
+    mTimeStats.onDestroy(getSequence());
 }
 
 void BufferLayer::useSurfaceDamage() {
@@ -234,27 +236,71 @@
     const auto& viewport = display->getViewport();
     Region visible = tr.transform(visibleRegion.intersect(viewport));
     const auto displayId = display->getId();
+    if (!hasHwcLayer(displayId)) {
+        ALOGE("[%s] failed to setPerFrameData: no HWC layer found (%d)",
+              mName.string(), displayId);
+        return;
+    }
+    auto& hwcInfo = getBE().mHwcLayers[displayId];
+    auto& hwcLayer = hwcInfo.layer;
+    auto error = hwcLayer->setVisibleRegion(visible);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
+              to_string(error).c_str(), static_cast<int32_t>(error));
+        visible.dump(LOG_TAG);
+    }
     getBE().compositionInfo.hwc.visibleRegion = visible;
+
+    error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
+              to_string(error).c_str(), static_cast<int32_t>(error));
+        surfaceDamageRegion.dump(LOG_TAG);
+    }
     getBE().compositionInfo.hwc.surfaceDamage = surfaceDamageRegion;
 
     // Sideband layers
     if (getBE().compositionInfo.hwc.sidebandStream.get()) {
         setCompositionType(displayId, HWC2::Composition::Sideband);
+        ALOGV("[%s] Requesting Sideband composition", mName.string());
+        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().compositionInfo.hwc.sidebandStream->handle(), to_string(error).c_str(),
+                  static_cast<int32_t>(error));
+        }
         getBE().compositionInfo.compositionType = HWC2::Composition::Sideband;
         return;
     }
 
-    if (getBE().compositionInfo.hwc.skipGeometry) {
-        // Device or Cursor layers
-        if (mPotentialCursor) {
-            ALOGV("[%s] Requesting Cursor composition", mName.string());
-            setCompositionType(displayId, HWC2::Composition::Cursor);
-        } else {
-            ALOGV("[%s] Requesting Device composition", mName.string());
-            setCompositionType(displayId, HWC2::Composition::Device);
-        }
+    // Device or Cursor layers
+    if (mPotentialCursor) {
+        ALOGV("[%s] Requesting Cursor composition", mName.string());
+        setCompositionType(displayId, HWC2::Composition::Cursor);
+    } else {
+        ALOGV("[%s] Requesting Device composition", mName.string());
+        setCompositionType(displayId, HWC2::Composition::Device);
     }
 
+    ALOGV("setPerFrameData: dataspace = %d", mCurrentDataSpace);
+    error = hwcLayer->setDataspace(mCurrentDataSpace);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
+              to_string(error).c_str(), static_cast<int32_t>(error));
+    }
+
+    const HdrMetadata& metadata = getDrawingHdrMetadata();
+    error = hwcLayer->setPerFrameMetadata(display->getSupportedPerFrameMetadata(), metadata);
+    if (error != HWC2::Error::None && error != HWC2::Error::Unsupported) {
+        ALOGE("[%s] Failed to set hdrMetadata: %s (%d)", mName.string(),
+              to_string(error).c_str(), static_cast<int32_t>(error));
+    }
+
+    error = hwcLayer->setColorTransform(getColorTransform());
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
+                to_string(error).c_str(), static_cast<int32_t>(error));
+    }
     getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
     getBE().compositionInfo.hwc.hdrMetadata = getDrawingHdrMetadata();
     getBE().compositionInfo.hwc.supportedPerFrameMetadata = display->getSupportedPerFrameMetadata();
@@ -291,8 +337,8 @@
     nsecs_t desiredPresentTime = getDesiredPresentTime();
     mFrameTracker.setDesiredPresentTime(desiredPresentTime);
 
-    const std::string layerName(getName().c_str());
-    mTimeStats.setDesiredTime(layerName, mCurrentFrameNumber, desiredPresentTime);
+    const int32_t layerID = getSequence();
+    mTimeStats.setDesiredTime(layerID, mCurrentFrameNumber, desiredPresentTime);
 
     std::shared_ptr<FenceTime> frameReadyFence = getCurrentFenceTime();
     if (frameReadyFence->isValid()) {
@@ -304,14 +350,14 @@
     }
 
     if (presentFence->isValid()) {
-        mTimeStats.setPresentFence(layerName, mCurrentFrameNumber, presentFence);
+        mTimeStats.setPresentFence(layerID, mCurrentFrameNumber, presentFence);
         mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
     } else if (mFlinger->getHwComposer().isConnected(HWC_DISPLAY_PRIMARY)) {
         // The HWC doesn't support present fences, so use the refresh
         // timestamp instead.
         const nsecs_t actualPresentTime =
                 mFlinger->getHwComposer().getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
-        mTimeStats.setPresentTime(layerName, mCurrentFrameNumber, actualPresentTime);
+        mTimeStats.setPresentTime(layerID, mCurrentFrameNumber, actualPresentTime);
         mFrameTracker.setActualPresentTime(actualPresentTime);
     }
 
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e75fbdf..e592a8b 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -227,6 +227,7 @@
     // BufferItem's that weren't actually queued. This can happen in shared
     // buffer mode.
     bool queuedBuffer = false;
+    const int32_t layerID = getSequence();
     LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
                     getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
                     getTransformToDisplayInverse(), mFreezeGeometryUpdates);
@@ -247,7 +248,7 @@
         // and return early
         if (queuedBuffer) {
             Mutex::Autolock lock(mQueueItemLock);
-            mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
+            mTimeStats.removeTimeRecord(layerID, mQueueItems[0].mFrameNumber);
             mQueueItems.removeAt(0);
             mQueuedFrames--;
         }
@@ -261,7 +262,7 @@
             Mutex::Autolock lock(mQueueItemLock);
             mQueueItems.clear();
             mQueuedFrames = 0;
-            mTimeStats.clearLayerRecord(getName().c_str());
+            mTimeStats.clearLayerRecord(layerID);
         }
 
         // Once we have hit this state, the shadow queue may no longer
@@ -282,14 +283,13 @@
         // Remove any stale buffers that have been dropped during
         // updateTexImage
         while (mQueueItems[0].mFrameNumber != currentFrameNumber) {
-            mTimeStats.removeTimeRecord(getName().c_str(), mQueueItems[0].mFrameNumber);
+            mTimeStats.removeTimeRecord(layerID, mQueueItems[0].mFrameNumber);
             mQueueItems.removeAt(0);
             mQueuedFrames--;
         }
 
-        const std::string layerName(getName().c_str());
-        mTimeStats.setAcquireFence(layerName, currentFrameNumber, mQueueItems[0].mFenceTime);
-        mTimeStats.setLatchTime(layerName, currentFrameNumber, latchTime);
+        mTimeStats.setAcquireFence(layerID, currentFrameNumber, mQueueItems[0].mFenceTime);
+        mTimeStats.setLatchTime(layerID, currentFrameNumber, latchTime);
 
         mQueueItems.removeAt(0);
     }
@@ -327,8 +327,22 @@
     return NO_ERROR;
 }
 
-void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>&) {
+void BufferQueueLayer::setHwcLayerBuffer(const sp<const DisplayDevice>& display) {
+    const auto displayId = display->getId();
+    auto& hwcInfo = getBE().mHwcLayers[displayId];
+    auto& hwcLayer = hwcInfo.layer;
+
+    uint32_t hwcSlot = 0;
+    sp<GraphicBuffer> hwcBuffer;
+    hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot, &hwcBuffer);
+
     auto acquireFence = mConsumer->getCurrentFence();
+    auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
+              getBE().compositionInfo.mBuffer->handle, to_string(error).c_str(),
+              static_cast<int32_t>(error));
+    }
     getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
     getBE().compositionInfo.mBuffer = mActiveBuffer;
     getBE().compositionInfo.hwc.fence = acquireFence;
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index e52b35a..5df8ade 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -377,6 +377,8 @@
         return NO_ERROR;
     }
 
+    const int32_t layerID = getSequence();
+
     // Reject if the layer is invalid
     uint32_t bufferWidth = s.buffer->width;
     uint32_t bufferHeight = s.buffer->height;
@@ -397,7 +399,7 @@
         ALOGE("[%s] rejecting buffer: "
               "bufferWidth=%d, bufferHeight=%d, front.active.{w=%d, h=%d}",
               mName.string(), bufferWidth, bufferHeight, s.active.w, s.active.h);
-        mTimeStats.removeTimeRecord(getName().c_str(), getFrameNumber());
+        mTimeStats.removeTimeRecord(layerID, getFrameNumber());
         return BAD_VALUE;
     }
 
@@ -405,7 +407,7 @@
     if (SyncFeatures::getInstance().useNativeFenceSync() && releaseFence != Fence::NO_FENCE) {
         // TODO(alecmouri): Fail somewhere upstream if the fence is invalid.
         if (!releaseFence->isValid()) {
-            mTimeStats.clearLayerRecord(getName().c_str());
+            mTimeStats.clearLayerRecord(layerID);
             return UNKNOWN_ERROR;
         }
 
@@ -415,7 +417,7 @@
         auto currentStatus = s.acquireFence->getStatus();
         if (currentStatus == Fence::Status::Invalid) {
             ALOGE("Existing fence has invalid state");
-            mTimeStats.clearLayerRecord(getName().c_str());
+            mTimeStats.clearLayerRecord(layerID);
             return BAD_VALUE;
         }
 
@@ -423,7 +425,7 @@
         if (incomingStatus == Fence::Status::Invalid) {
             ALOGE("New fence has invalid state");
             mDrawingState.acquireFence = releaseFence;
-            mTimeStats.clearLayerRecord(getName().c_str());
+            mTimeStats.clearLayerRecord(layerID);
             return BAD_VALUE;
         }
 
@@ -439,7 +441,7 @@
                 // synchronization is broken, the best we can do is hope fences
                 // signal in order so the new fence will act like a union
                 mDrawingState.acquireFence = releaseFence;
-                mTimeStats.clearLayerRecord(getName().c_str());
+                mTimeStats.clearLayerRecord(layerID);
                 return BAD_VALUE;
             }
             mDrawingState.acquireFence = mergedFence;
@@ -462,16 +464,16 @@
         // a GL-composited layer) not at all.
         status_t err = bindTextureImage();
         if (err != NO_ERROR) {
-            mTimeStats.clearLayerRecord(getName().c_str());
+            mTimeStats.clearLayerRecord(layerID);
             return BAD_VALUE;
         }
     }
 
     // TODO(marissaw): properly support mTimeStats
-    const std::string layerName(getName().c_str());
-    mTimeStats.setPostTime(getName().c_str(), getFrameNumber(), latchTime);
-    mTimeStats.setAcquireFence(layerName, getFrameNumber(), getCurrentFenceTime());
-    mTimeStats.setLatchTime(layerName, getFrameNumber(), latchTime);
+    mTimeStats.setLayerName(layerID, getName().c_str());
+    mTimeStats.setPostTime(layerID, getFrameNumber(), latchTime);
+    mTimeStats.setAcquireFence(layerID, getFrameNumber(), getCurrentFenceTime());
+    mTimeStats.setLatchTime(layerID, getFrameNumber(), latchTime);
 
     return NO_ERROR;
 }
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 3a554c9..263f872 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -62,20 +62,64 @@
     const auto& viewport = display->getViewport();
     Region visible = tr.transform(visibleRegion.intersect(viewport));
     const auto displayId = display->getId();
+    if (!hasHwcLayer(displayId)) {
+        ALOGE("[%s] failed to setPerFrameData: no HWC layer found (%d)",
+              mName.string(), displayId);
+        return;
+    }
+    auto& hwcInfo = getBE().mHwcLayers[displayId];
+    auto& hwcLayer = hwcInfo.layer;
+    auto error = hwcLayer->setVisibleRegion(visible);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
+              to_string(error).c_str(), static_cast<int32_t>(error));
+        visible.dump(LOG_TAG);
+    }
     getBE().compositionInfo.hwc.visibleRegion = visible;
-    getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
 
     setCompositionType(displayId, HWC2::Composition::SolidColor);
+
+    error = hwcLayer->setDataspace(mCurrentDataSpace);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mCurrentDataSpace,
+              to_string(error).c_str(), static_cast<int32_t>(error));
+    }
     getBE().compositionInfo.hwc.dataspace = mCurrentDataSpace;
 
     half4 color = getColor();
-    getBE().compositionInfo.hwc.color = {static_cast<uint8_t>(std::round(255.0f * color.r)),
-                                         static_cast<uint8_t>(std::round(255.0f * color.g)),
-                                         static_cast<uint8_t>(std::round(255.0f * color.b)), 255};
+    error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f * color.r)),
+                                static_cast<uint8_t>(std::round(255.0f * color.g)),
+                                static_cast<uint8_t>(std::round(255.0f * color.b)), 255});
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set color: %s (%d)", mName.string(), to_string(error).c_str(),
+              static_cast<int32_t>(error));
+    }
+    getBE().compositionInfo.hwc.color = { static_cast<uint8_t>(std::round(255.0f * color.r)),
+                                      static_cast<uint8_t>(std::round(255.0f * color.g)),
+                                      static_cast<uint8_t>(std::round(255.0f * color.b)), 255 };
 
     // Clear out the transform, because it doesn't make sense absent a source buffer
+    error = hwcLayer->setTransform(HWC2::Transform::None);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(), to_string(error).c_str(),
+              static_cast<int32_t>(error));
+    }
     getBE().compositionInfo.hwc.transform = HWC2::Transform::None;
+
+    error = hwcLayer->setColorTransform(getColorTransform());
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to setColorTransform: %s (%d)", mName.string(),
+                to_string(error).c_str(), static_cast<int32_t>(error));
+    }
     getBE().compositionInfo.hwc.colorTransform = getColorTransform();
+
+    error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
+              to_string(error).c_str(), static_cast<int32_t>(error));
+        surfaceDamageRegion.dump(LOG_TAG);
+    }
+    getBE().compositionInfo.hwc.surfaceDamage = surfaceDamageRegion;
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 60cad02..6f645df 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -37,8 +37,8 @@
 #include <ui/DebugUtils.h>
 #include <ui/DisplayInfo.h>
 #include <ui/PixelFormat.h>
-#include <utils/RefBase.h>
 #include <utils/Log.h>
+#include <utils/RefBase.h>
 
 #include "DisplayHardware/DisplaySurface.h"
 #include "DisplayHardware/HWComposer.h"
@@ -66,7 +66,8 @@
 namespace {
 
 // ordered list of known SDR color modes
-const std::array<ColorMode, 2> sSdrColorModes = {
+const std::array<ColorMode, 3> sSdrColorModes = {
+        ColorMode::DISPLAY_BT2020,
         ColorMode::DISPLAY_P3,
         ColorMode::SRGB,
 };
@@ -96,6 +97,8 @@
             return Dataspace::SRGB;
         case ColorMode::DISPLAY_P3:
             return Dataspace::DISPLAY_P3;
+        case ColorMode::DISPLAY_BT2020:
+            return Dataspace::DISPLAY_BT2020;
         case ColorMode::BT2100_HLG:
             return Dataspace::BT2020_HLG;
         case ColorMode::BT2100_PQ:
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 163b26c..f0bccaa 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -354,16 +354,26 @@
 {
     Error error = kDefaultError;
 
-    if (mClient_2_2) {
-        mClient_2_2->getColorModes_2_2(display,
-                [&](const auto& tmpError, const auto& tmpModes) {
-                    error = tmpError;
-                    if (error != Error::NONE) {
-                        return;
-                    }
+    if (mClient_2_3) {
+        mClient_2_3->getColorModes_2_3(display, [&](const auto& tmpError, const auto& tmpModes) {
+            error = tmpError;
+            if (error != Error::NONE) {
+                return;
+            }
 
-                    *outModes = tmpModes;
-                });
+            *outModes = tmpModes;
+        });
+    } else if (mClient_2_2) {
+        mClient_2_2->getColorModes_2_2(display, [&](const auto& tmpError, const auto& tmpModes) {
+            error = tmpError;
+            if (error != Error::NONE) {
+                return;
+            }
+
+            for (types::V1_1::ColorMode colorMode : tmpModes) {
+                outModes->push_back(static_cast<ColorMode>(colorMode));
+            }
+        });
     } else {
         mClient->getColorModes(display,
                 [&](const auto& tmpError, const auto& tmpModes) {
@@ -555,8 +565,11 @@
         RenderIntent renderIntent)
 {
     hardware::Return<Error> ret(kDefaultError);
-    if (mClient_2_2) {
-        ret = mClient_2_2->setColorMode_2_2(display, mode, renderIntent);
+    if (mClient_2_3) {
+        ret = mClient_2_3->setColorMode_2_3(display, mode, renderIntent);
+    } else if (mClient_2_2) {
+        ret = mClient_2_2->setColorMode_2_2(display, static_cast<types::V1_1::ColorMode>(mode),
+                                            renderIntent);
     } else {
         ret = mClient->setColorMode(display,
                 static_cast<types::V1_0::ColorMode>(mode));
@@ -934,15 +947,22 @@
     }
 
     Error error = kDefaultError;
-    mClient_2_2->getRenderIntents(display, colorMode,
-            [&](const auto& tmpError, const auto& tmpKeys) {
+
+    auto getRenderIntentsLambda = [&](const auto& tmpError, const auto& tmpKeys) {
         error = tmpError;
         if (error != Error::NONE) {
             return;
         }
 
         *outRenderIntents = tmpKeys;
-    });
+    };
+
+    if (mClient_2_3) {
+        mClient_2_3->getRenderIntents_2_3(display, colorMode, getRenderIntentsLambda);
+    } else {
+        mClient_2_2->getRenderIntents(display, static_cast<types::V1_1::ColorMode>(colorMode),
+                                      getRenderIntentsLambda);
+    }
 
     return error;
 }
@@ -955,14 +975,14 @@
     }
 
     Error error = kDefaultError;
-    mClient_2_2->getDataspaceSaturationMatrix(dataspace, [&](const auto& tmpError, const auto& tmpMatrix) {
-        error = tmpError;
-        if (error != Error::NONE) {
-            return;
-        }
-
-        *outMatrix = mat4(tmpMatrix.data());
-    });
+    mClient_2_2->getDataspaceSaturationMatrix(static_cast<types::V1_1::Dataspace>(dataspace),
+                                              [&](const auto& tmpError, const auto& tmpMatrix) {
+                                                  error = tmpError;
+                                                  if (error != Error::NONE) {
+                                                      return;
+                                                  }
+                                                  *outMatrix = mat4(tmpMatrix.data());
+                                              });
 
     return error;
 }
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index 94be6e9..4188352 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -49,10 +49,10 @@
 using types::V1_0::Hdr;
 using types::V1_0::Transform;
 
-using types::V1_1::ColorMode;
-using types::V1_1::Dataspace;
 using types::V1_1::PixelFormat;
 using types::V1_1::RenderIntent;
+using types::V1_2::ColorMode;
+using types::V1_2::Dataspace;
 
 using V2_1::Config;
 using V2_1::Display;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7e6b5d3..88c3c8a 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -458,18 +458,6 @@
     }
     auto& hwcInfo = getBE().mHwcLayers[displayId];
 
-    // Device or Cursor layers
-    if (mPotentialCursor) {
-        ALOGV("[%s] Requesting Cursor composition", mName.string());
-        setCompositionType(displayId, HWC2::Composition::Cursor);
-    } else {
-        ALOGV("[%s] Requesting Device composition", mName.string());
-        setCompositionType(displayId, HWC2::Composition::Device);
-    }
-
-    // Need to program geometry parts
-    getBE().compositionInfo.hwc.skipGeometry = false;
-
     // enable this layer
     hwcInfo.forceClientComposition = false;
 
@@ -477,6 +465,8 @@
         hwcInfo.forceClientComposition = true;
     }
 
+    auto& hwcLayer = hwcInfo.layer;
+
     // this gives us only the "orientation" component of the transform
     const State& s(getDrawingState());
     auto blendMode = HWC2::BlendMode::None;
@@ -484,6 +474,12 @@
         blendMode =
                 mPremultipliedAlpha ? HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
     }
+    auto error = hwcLayer->setBlendMode(blendMode);
+    ALOGE_IF(error != HWC2::Error::None,
+             "[%s] Failed to set blend mode %s:"
+             " %s (%d)",
+             mName.string(), to_string(blendMode).c_str(), to_string(error).c_str(),
+             static_cast<int32_t>(error));
     getBE().compositionInfo.hwc.blendMode = blendMode;
 
     // apply the layer's transform, followed by the display's global transform
@@ -523,14 +519,39 @@
     }
     const ui::Transform& tr = display->getTransform();
     Rect transformedFrame = tr.transform(frame);
+    error = hwcLayer->setDisplayFrame(transformedFrame);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)", mName.string(),
+              transformedFrame.left, transformedFrame.top, transformedFrame.right,
+              transformedFrame.bottom, to_string(error).c_str(), static_cast<int32_t>(error));
+    } else {
+        hwcInfo.displayFrame = transformedFrame;
+    }
     getBE().compositionInfo.hwc.displayFrame = transformedFrame;
 
     FloatRect sourceCrop = computeCrop(display);
+    error = hwcLayer->setSourceCrop(sourceCrop);
+    if (error != HWC2::Error::None) {
+        ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
+              "%s (%d)",
+              mName.string(), sourceCrop.left, sourceCrop.top, sourceCrop.right, sourceCrop.bottom,
+              to_string(error).c_str(), static_cast<int32_t>(error));
+    } else {
+        hwcInfo.sourceCrop = sourceCrop;
+    }
     getBE().compositionInfo.hwc.sourceCrop = sourceCrop;
 
     float alpha = static_cast<float>(getAlpha());
+    error = hwcLayer->setPlaneAlpha(alpha);
+    ALOGE_IF(error != HWC2::Error::None,
+             "[%s] Failed to set plane alpha %.3f: "
+             "%s (%d)",
+             mName.string(), alpha, to_string(error).c_str(), static_cast<int32_t>(error));
     getBE().compositionInfo.hwc.alpha = alpha;
 
+    error = hwcLayer->setZOrder(z);
+    ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set Z %u: %s (%d)", mName.string(), z,
+             to_string(error).c_str(), static_cast<int32_t>(error));
     getBE().compositionInfo.hwc.z = z;
 
     int type = s.type;
@@ -544,6 +565,10 @@
         }
     }
 
+    error = hwcLayer->setInfo(type, appId);
+    ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set info (%d)", mName.string(),
+             static_cast<int32_t>(error));
+
     getBE().compositionInfo.hwc.type = type;
     getBE().compositionInfo.hwc.appId = appId;
 
@@ -583,9 +608,16 @@
     if (orientation & ui::Transform::ROT_INVALID) {
         // we can only handle simple transformation
         hwcInfo.forceClientComposition = true;
+        getBE().mHwcLayers[displayId].compositionType = HWC2::Composition::Client;
     } else {
         auto transform = static_cast<HWC2::Transform>(orientation);
         hwcInfo.transform = transform;
+        auto error = hwcLayer->setTransform(transform);
+        ALOGE_IF(error != HWC2::Error::None,
+                 "[%s] Failed to set transform %s: "
+                 "%s (%d)",
+                 mName.string(), to_string(transform).c_str(), to_string(error).c_str(),
+                 static_cast<int32_t>(error));
         getBE().compositionInfo.hwc.transform = transform;
     }
 }
@@ -666,16 +698,25 @@
     clearWithOpenGL(renderArea, 0, 0, 0, 0);
 }
 
-void Layer::setCompositionType(int32_t displayId, HWC2::Composition type, bool /*callIntoHwc*/) {
+void Layer::setCompositionType(int32_t displayId, HWC2::Composition type, bool callIntoHwc) {
     if (getBE().mHwcLayers.count(displayId) == 0) {
         ALOGE("setCompositionType called without a valid HWC layer");
         return;
-    } else {
-        if (getBE().mHwcLayers[displayId].compositionType != type) {
-            ALOGV("setCompositionType: Changing compositionType from %s to %s",
-                    to_string(getBE().mHwcLayers[displayId].compositionType).c_str(),
-                    to_string(type).c_str());
-            getBE().mHwcLayers[displayId].compositionType = type;
+    }
+    auto& hwcInfo = getBE().mHwcLayers[displayId];
+    auto& hwcLayer = hwcInfo.layer;
+    ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", (hwcLayer)->getId(), to_string(type).c_str(),
+          static_cast<int>(callIntoHwc));
+    if (hwcInfo.compositionType != type) {
+        ALOGV("    actually setting");
+        hwcInfo.compositionType = type;
+        if (callIntoHwc) {
+            auto error = (hwcLayer)->setCompositionType(type);
+            ALOGE_IF(error != HWC2::Error::None,
+                     "[%s] Failed to set "
+                     "composition type %s: %s (%d)",
+                     mName.string(), to_string(type).c_str(), to_string(error).c_str(),
+                     static_cast<int32_t>(error));
         }
     }
 }
@@ -1429,14 +1470,15 @@
 void Layer::onDisconnect() {
     Mutex::Autolock lock(mFrameEventHistoryMutex);
     mFrameEventHistory.onDisconnect();
-    mTimeStats.onDisconnect(getName().c_str());
+    mTimeStats.onDisconnect(getSequence());
 }
 
 void Layer::addAndGetFrameTimestamps(const NewFrameEventsEntry* newTimestamps,
                                      FrameEventHistoryDelta* outDelta) {
     if (newTimestamps) {
-        mTimeStats.setPostTime(getName().c_str(), newTimestamps->frameNumber,
-                               newTimestamps->postedTime);
+        const int32_t layerID = getSequence();
+        mTimeStats.setLayerName(layerID, getName().c_str());
+        mTimeStats.setPostTime(layerID, newTimestamps->frameNumber, newTimestamps->postedTime);
     }
 
     Mutex::Autolock lock(mFrameEventHistoryMutex);
diff --git a/services/surfaceflinger/LayerBE.cpp b/services/surfaceflinger/LayerBE.cpp
index c9b7933..70b00dd 100644
--- a/services/surfaceflinger/LayerBE.cpp
+++ b/services/surfaceflinger/LayerBE.cpp
@@ -65,9 +65,7 @@
 }
 
 void LayerBE::onLayerDisplayed(const sp<Fence>& releaseFence) {
-    if (mLayer) {
-        mLayer->onLayerDisplayed(releaseFence);
-    }
+    mLayer->onLayerDisplayed(releaseFence);
 }
 
 void LayerBE::clear(renderengine::RenderEngine& engine) {
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
index d63d16f..463c46c 100644
--- a/services/surfaceflinger/LayerBE.h
+++ b/services/surfaceflinger/LayerBE.h
@@ -34,14 +34,13 @@
 
 struct CompositionInfo {
     std::string layerName;
-    HWC2::Composition compositionType = HWC2::Composition::Invalid;
+    HWC2::Composition compositionType;
     bool firstClear = false;
     sp<GraphicBuffer> mBuffer = nullptr;
     int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
     std::shared_ptr<LayerBE> layer;
     struct {
         std::shared_ptr<HWC2::Layer> hwcLayer;
-        bool skipGeometry = true;
         int32_t displayId = -1;
         sp<Fence> fence;
         HWC2::BlendMode blendMode = HWC2::BlendMode::Invalid;
diff --git a/services/surfaceflinger/RenderEngine/TEST_MAPPING b/services/surfaceflinger/RenderEngine/TEST_MAPPING
new file mode 100644
index 0000000..995dba1
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "librenderengine_test"
+    }
+  ]
+}
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
index 5c4c3d5..dbf50c5 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.cpp
@@ -650,6 +650,13 @@
     } while (true);
 }
 
+status_t GLES20RenderEngine::drawLayers(const DisplaySettings& /*settings*/,
+                                        const std::vector<LayerSettings>& /*layers*/,
+                                        ANativeWindowBuffer* const /*buffer*/,
+                                        base::unique_fd* /*displayFence*/) const {
+    return NO_ERROR;
+}
+
 void GLES20RenderEngine::setViewportAndProjection(size_t vpw, size_t vph, Rect sourceCrop,
                                                   ui::Transform::orientation_flags rotation) {
     int32_t l = sourceCrop.left;
diff --git a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
index 4f03a90..b08e096 100644
--- a/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/gl/GLES20RenderEngine.h
@@ -73,6 +73,10 @@
     void unbindFrameBuffer(Framebuffer* framebuffer) override;
     void checkErrors() const override;
 
+    status_t drawLayers(const DisplaySettings& settings, const std::vector<LayerSettings>& layers,
+                        ANativeWindowBuffer* const buffer,
+                        base::unique_fd* displayFence) const override;
+
     // internal to RenderEngine
     EGLDisplay getEGLDisplay() const { return mEGLDisplay; }
     EGLConfig getEGLConfig() const { return mEGLConfig; }
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/DisplaySettings.h b/services/surfaceflinger/RenderEngine/include/renderengine/DisplaySettings.h
new file mode 100644
index 0000000..5941cdf
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/DisplaySettings.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2018 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 <math/mat4.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+
+namespace android {
+namespace renderengine {
+
+// DisplaySettings contains the settings that are applicable when drawing all
+// layers for a given display.
+struct DisplaySettings {
+    // Rectangle describing the physical display. We will project from the
+    // logical clip onto this rectangle.
+    Rect physicalDisplay;
+
+    // Rectangle bounded by the x,y- clipping planes in the logical display, so
+    // that the orthographic projection matrix can be computed. When
+    // constructing this matrix, z-coordinate bound are assumed to be at z=0 and
+    // z=1.
+    Rect clip;
+
+    // Global transform to apply to all layers.
+    mat4 globalTransform;
+
+    // Maximum luminance pulled from the display's HDR capabilities.
+    float maxLuminence;
+
+    // Output dataspace that will be populated if wide color gamut is used, or
+    // DataSpace::UNKNOWN otherwise.
+    ui::Dataspace outputDataspace;
+
+    // Additional color transform to apply in linear space after transforming
+    // to the output dataspace.
+    mat4 colorTransform;
+
+    // Region that will be cleared to (0, 0, 0, 0) prior to rendering.
+    // clearRegion will first be transformed by globalTransform so that it will
+    // be in the same coordinate space as the rendered layers.
+    Region clearRegion;
+};
+
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/LayerSettings.h b/services/surfaceflinger/RenderEngine/include/renderengine/LayerSettings.h
new file mode 100644
index 0000000..facea21
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/LayerSettings.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2018 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 <math/mat4.h>
+#include <math/vec3.h>
+#include <renderengine/Texture.h>
+#include <ui/FloatRect.h>
+#include <ui/GraphicBuffer.h>
+#include <ui/GraphicTypes.h>
+#include <ui/Rect.h>
+#include <ui/Region.h>
+#include <ui/Transform.h>
+
+namespace android {
+namespace renderengine {
+
+// Metadata describing the input buffer to render from.
+struct Buffer {
+    // Buffer containing the image that we will render.
+    // If buffer == nullptr, then the rest of the fields in this struct will be
+    // ignored.
+    sp<GraphicBuffer> buffer;
+
+    // Texture identifier to bind the external texture to.
+    // TODO(alecmouri): This is GL-specific...make the type backend-agnostic.
+    uint32_t textureName;
+
+    // Whether to use filtering when rendering the texture.
+    bool useTextureFiltering;
+
+    // Transform matrix to apply to texture coordinates.
+    mat4 textureTransform;
+
+    // Wheteher to use pre-multiplied alpha
+    bool usePremultipliedAlpha;
+
+    // HDR color-space setting for Y410.
+    bool isY410BT2020;
+};
+
+// Metadata describing the layer geometry.
+struct Geometry {
+    // Boundaries of the layer.
+    FloatRect boundaries;
+
+    // Transform matrix to apply to mesh coordinates.
+    mat4 positionTransform;
+};
+
+// Descriptor of the source pixels for this layer.
+struct PixelSource {
+    // Source buffer
+    Buffer buffer;
+
+    // The solid color with which to fill the layer.
+    // This should only be populated if we don't render from an application
+    // buffer.
+    half3 solidColor;
+};
+
+// The settings that RenderEngine requires for correctly rendering a Layer.
+struct LayerSettings {
+    // Geometry information
+    Geometry geometry;
+
+    // Source pixels for this layer.
+    PixelSource source;
+
+    // Alpha option to apply to the source pixels
+    half alpha;
+
+    // Color space describing how the source pixels should be interpreted.
+    ui::Dataspace sourceDataspace;
+};
+
+} // namespace renderengine
+} // namespace android
diff --git a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h b/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
index 122271f..f5d3d6b 100644
--- a/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/include/renderengine/RenderEngine.h
@@ -23,8 +23,10 @@
 
 #include <android-base/unique_fd.h>
 #include <math/mat4.h>
+#include <renderengine/DisplaySettings.h>
 #include <renderengine/Framebuffer.h>
 #include <renderengine/Image.h>
+#include <renderengine/LayerSettings.h>
 #include <ui/GraphicTypes.h>
 #include <ui/Transform.h>
 
@@ -64,6 +66,11 @@
 
     virtual ~RenderEngine() = 0;
 
+    // ----- BEGIN DEPRECATED INTERFACE -----
+    // This interface, while still in use until a suitable replacement is built,
+    // should be considered deprecated, minus some methods which still may be
+    // used to support legacy behavior.
+
     virtual std::unique_ptr<Framebuffer> createFramebuffer() = 0;
     virtual std::unique_ptr<Surface> createSurface() = 0;
     virtual std::unique_ptr<Image> createImage() = 0;
@@ -133,6 +140,37 @@
     // queries
     virtual size_t getMaxTextureSize() const = 0;
     virtual size_t getMaxViewportDims() const = 0;
+
+    // ----- END DEPRECATED INTERFACE -----
+
+    // ----- BEGIN NEW INTERFACE -----
+
+    // Renders layers for a particular display via GPU composition. This method
+    // should be called for every display that needs to be rendered via the GPU.
+    // @param settings The display-wide settings that should be applied prior to
+    // drawing any layers.
+    // @param layers The layers to draw onto the display, in Z-order.
+    // @param buffer The buffer which will be drawn to. This buffer will be
+    // ready once displayFence fires.
+    // @param displayFence A pointer to a fence, which will fire when the buffer
+    // has been drawn to and is ready to be examined. The fence will be
+    // initialized by this method. The caller will be responsible for owning the
+    // fence.
+    // @return An error code indicating whether drawing was successful. For
+    // now, this always returns NO_ERROR.
+    // TODO(alecmouri): Consider making this a multi-display API, so that the
+    // caller deoes not need to handle multiple fences.
+    virtual status_t drawLayers(const DisplaySettings& settings,
+                                const std::vector<LayerSettings>& layers,
+                                ANativeWindowBuffer* const buffer,
+                                base::unique_fd* displayFence) const = 0;
+
+    // TODO(alecmouri): Expose something like bindTexImage() so that devices
+    // that don't support native sync fences can get rid of code duplicated
+    // between BufferStateLayer and BufferQueueLayer for binding an external
+    // texture.
+
+    // TODO(alecmouri): Add API to help with managing a texture pool.
 };
 
 class BindNativeBufferAsFramebuffer {
diff --git a/services/surfaceflinger/RenderEngine/tests/Android.bp b/services/surfaceflinger/RenderEngine/tests/Android.bp
new file mode 100644
index 0000000..65b7c82
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/tests/Android.bp
@@ -0,0 +1,36 @@
+// Copyright 2018 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.
+
+cc_test {
+    name: "librenderengine_test",
+    defaults: ["surfaceflinger_defaults"],
+    test_suites: ["device-tests"],
+    srcs: [
+        "RenderEngineTest.cpp",
+    ],
+    static_libs: [
+        "libgmock",
+        "librenderengine",
+    ],
+    shared_libs: [
+        "libcutils",
+        "libEGL",
+        "libGLESv2",
+        "libgui",
+        "liblog",
+        "libnativewindow",
+        "libui",
+        "libutils",
+    ],
+}
diff --git a/services/surfaceflinger/RenderEngine/tests/RenderEngineTest.cpp b/services/surfaceflinger/RenderEngine/tests/RenderEngineTest.cpp
new file mode 100644
index 0000000..345c7ea
--- /dev/null
+++ b/services/surfaceflinger/RenderEngine/tests/RenderEngineTest.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2018 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 <gtest/gtest.h>
+
+#include <renderengine/RenderEngine.h>
+#include <ui/PixelFormat.h>
+
+namespace android {
+
+class RenderEngineTest : public ::testing::Test {
+public:
+    RenderEngineTest() {
+        // Initialize with some sane defaults.
+        // TODO(alecmouri): This should probably be the same instance used by
+        // SurfaceFlinger eventually.
+        mRE = renderengine::RenderEngine::create(static_cast<int32_t>(ui::PixelFormat::RGBA_8888),
+                                                 0);
+    }
+
+    status_t drawEmptyLayers() {
+        renderengine::DisplaySettings settings;
+        std::vector<renderengine::LayerSettings> layers;
+        // Meaningless buffer since we don't do any drawing
+        sp<GraphicBuffer> buffer = new GraphicBuffer();
+        base::unique_fd fence;
+        return mRE->drawLayers(settings, layers, buffer->getNativeBuffer(), &fence);
+    }
+
+private:
+    std::unique_ptr<renderengine::RenderEngine> mRE;
+};
+
+TEST_F(RenderEngineTest, drawLayers_noLayersToDraw_works) {
+    status_t result = drawEmptyLayers();
+    ASSERT_EQ(NO_ERROR, result);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index f0723e8..4a96e89 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -124,6 +124,7 @@
         case ColorMode::ADOBE_RGB:
         case ColorMode::DCI_P3:
         case ColorMode::BT2020:
+        case ColorMode::DISPLAY_BT2020:
         case ColorMode::BT2100_PQ:
         case ColorMode::BT2100_HLG:
             return true;
@@ -1522,13 +1523,8 @@
     preComposition();
     rebuildLayerStacks();
     calculateWorkingSet();
-
     for (const auto& [token, display] : mDisplays) {
-        const auto displayId = display->getId();
         beginFrame(display);
-        for (auto& compositionInfo : getBE().mCompositionInfo[displayId]) {
-            setUpHWComposer(compositionInfo);
-        }
         prepareFrame(display);
         doDebugFlashRegions(display, repaintEverything);
         doComposition(display, repaintEverything);
@@ -1909,6 +1905,8 @@
         mTimeStats.incrementClientCompositionFrames();
     }
 
+    mTimeStats.setPresentFenceGlobal(presentFenceTime);
+
     if (display && getHwComposer().isConnected(display->getId()) &&
         display->getPowerMode() == HWC_POWER_MODE_OFF) {
         return;
@@ -2008,6 +2006,7 @@
 // can only be one of
 //  - Dataspace::SRGB (use legacy dataspace and let HWC saturate when colors are enhanced)
 //  - Dataspace::DISPLAY_P3
+//  - Dataspace::DISPLAY_BT2020
 // The returned HDR data space is one of
 //  - Dataspace::UNKNOWN
 //  - Dataspace::BT2020_HLG
@@ -2021,6 +2020,12 @@
         switch (layer->getDataSpace()) {
             case Dataspace::V0_SCRGB:
             case Dataspace::V0_SCRGB_LINEAR:
+            case Dataspace::BT2020:
+            case Dataspace::BT2020_ITU:
+            case Dataspace::BT2020_LINEAR:
+            case Dataspace::DISPLAY_BT2020:
+                bestDataSpace = Dataspace::DISPLAY_BT2020;
+                break;
             case Dataspace::DISPLAY_P3:
                 bestDataSpace = Dataspace::DISPLAY_P3;
                 break;
@@ -2081,127 +2086,6 @@
     display->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
 }
 
-void SurfaceFlinger::configureSidebandComposition(const CompositionInfo& compositionInfo) const
-{
-    HWC2::Error error;
-    LOG_ALWAYS_FATAL_IF(compositionInfo.hwc.sidebandStream == nullptr,
-                        "CompositionType is sideband, but sideband stream is nullptr");
-    error = (compositionInfo.hwc.hwcLayer)
-                    ->setSidebandStream(compositionInfo.hwc.sidebandStream->handle());
-    if (error != HWC2::Error::None) {
-        ALOGE("[SF] Failed to set sideband stream %p: %s (%d)",
-                compositionInfo.hwc.sidebandStream->handle(), to_string(error).c_str(),
-                static_cast<int32_t>(error));
-    }
-}
-
-void SurfaceFlinger::configureHwcCommonData(const CompositionInfo& compositionInfo) const
-{
-    HWC2::Error error;
-
-    if (!compositionInfo.hwc.skipGeometry) {
-        error = (compositionInfo.hwc.hwcLayer)->setBlendMode(compositionInfo.hwc.blendMode);
-        ALOGE_IF(error != HWC2::Error::None,
-                 "[SF] Failed to set blend mode %s:"
-                 " %s (%d)",
-                 to_string(compositionInfo.hwc.blendMode).c_str(), to_string(error).c_str(),
-                 static_cast<int32_t>(error));
-
-        error = (compositionInfo.hwc.hwcLayer)->setDisplayFrame(compositionInfo.hwc.displayFrame);
-        ALOGE_IF(error != HWC2::Error::None,
-                "[SF] Failed to set the display frame [%d, %d, %d, %d] %s (%d)",
-                compositionInfo.hwc.displayFrame.left,
-                compositionInfo.hwc.displayFrame.right,
-                compositionInfo.hwc.displayFrame.top,
-                compositionInfo.hwc.displayFrame.bottom,
-                to_string(error).c_str(), static_cast<int32_t>(error));
-
-        error = (compositionInfo.hwc.hwcLayer)->setSourceCrop(compositionInfo.hwc.sourceCrop);
-        ALOGE_IF(error != HWC2::Error::None,
-                "[SF] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: %s (%d)",
-                compositionInfo.hwc.sourceCrop.left,
-                compositionInfo.hwc.sourceCrop.right,
-                compositionInfo.hwc.sourceCrop.top,
-                compositionInfo.hwc.sourceCrop.bottom,
-                to_string(error).c_str(), static_cast<int32_t>(error));
-
-        error = (compositionInfo.hwc.hwcLayer)->setPlaneAlpha(compositionInfo.hwc.alpha);
-        ALOGE_IF(error != HWC2::Error::None,
-                 "[SF] Failed to set plane alpha %.3f: "
-                 "%s (%d)",
-                 compositionInfo.hwc.alpha,
-                 to_string(error).c_str(), static_cast<int32_t>(error));
-
-
-        error = (compositionInfo.hwc.hwcLayer)->setZOrder(compositionInfo.hwc.z);
-        ALOGE_IF(error != HWC2::Error::None,
-                "[SF] Failed to set Z %u: %s (%d)",
-                compositionInfo.hwc.z,
-                to_string(error).c_str(), static_cast<int32_t>(error));
-
-        error = (compositionInfo.hwc.hwcLayer)
-                        ->setInfo(compositionInfo.hwc.type, compositionInfo.hwc.appId);
-        ALOGE_IF(error != HWC2::Error::None,
-                "[SF] Failed to set info (%d)",
-                static_cast<int32_t>(error));
-
-        error = (compositionInfo.hwc.hwcLayer)->setTransform(compositionInfo.hwc.transform);
-        ALOGE_IF(error != HWC2::Error::None,
-                 "[SF] Failed to set transform %s: "
-                 "%s (%d)",
-                 to_string(compositionInfo.hwc.transform).c_str(), to_string(error).c_str(),
-                 static_cast<int32_t>(error));
-    }
-
-    error = (compositionInfo.hwc.hwcLayer)->setCompositionType(compositionInfo.compositionType);
-    ALOGE_IF(error != HWC2::Error::None,
-            "[SF] Failed to set composition type: %s (%d)",
-                to_string(error).c_str(), static_cast<int32_t>(error));
-
-    error = (compositionInfo.hwc.hwcLayer)->setDataspace(compositionInfo.hwc.dataspace);
-    ALOGE_IF(error != HWC2::Error::None,
-            "[SF] Failed to set dataspace: %s (%d)",
-            to_string(error).c_str(), static_cast<int32_t>(error));
-
-    error = (compositionInfo.hwc.hwcLayer)->setPerFrameMetadata(
-            compositionInfo.hwc.supportedPerFrameMetadata, compositionInfo.hwc.hdrMetadata);
-    ALOGE_IF(error != HWC2::Error::None && error != HWC2::Error::Unsupported,
-            "[SF] Failed to set hdrMetadata: %s (%d)",
-            to_string(error).c_str(), static_cast<int32_t>(error));
-
-    if (compositionInfo.compositionType == HWC2::Composition::SolidColor) {
-        error = (compositionInfo.hwc.hwcLayer)->setColor(compositionInfo.hwc.color);
-        ALOGE_IF(error != HWC2::Error::None,
-                "[SF] Failed to set color: %s (%d)",
-                to_string(error).c_str(), static_cast<int32_t>(error));
-    }
-
-    error = (compositionInfo.hwc.hwcLayer)->setVisibleRegion(compositionInfo.hwc.visibleRegion);
-    ALOGE_IF(error != HWC2::Error::None,
-            "[SF] Failed to set visible region: %s (%d)",
-            to_string(error).c_str(), static_cast<int32_t>(error));
-
-    error = (compositionInfo.hwc.hwcLayer)->setSurfaceDamage(compositionInfo.hwc.surfaceDamage);
-    ALOGE_IF(error != HWC2::Error::None,
-            "[SF] Failed to set surface damage: %s (%d)",
-            to_string(error).c_str(), static_cast<int32_t>(error));
-
-    error = (compositionInfo.hwc.hwcLayer)->setColorTransform(compositionInfo.hwc.colorTransform);
-}
-
-void SurfaceFlinger::configureDeviceComposition(const CompositionInfo& compositionInfo) const
-{
-    HWC2::Error error;
-
-    if (compositionInfo.hwc.fence) {
-        error = (compositionInfo.hwc.hwcLayer)->setBuffer(compositionInfo.mBufferSlot,
-                compositionInfo.mBuffer, compositionInfo.hwc.fence);
-        ALOGE_IF(error != HWC2::Error::None,
-                "[SF] Failed to set buffer: %s (%d)",
-                to_string(error).c_str(), static_cast<int32_t>(error));
-    }
-}
-
 void SurfaceFlinger::beginFrame(const sp<DisplayDevice>& display)
 {
     bool dirty = !display->getDirtyRegion(false).isEmpty();
@@ -2247,42 +2131,6 @@
              display->getId(), result, strerror(-result));
 }
 
-void SurfaceFlinger::setUpHWComposer(const CompositionInfo& compositionInfo) {
-    ATRACE_CALL();
-    ALOGV("setUpHWComposer");
-
-    switch (compositionInfo.compositionType)
-    {
-        case HWC2::Composition::Invalid:
-            break;
-
-        case HWC2::Composition::Client:
-            if (compositionInfo.hwc.hwcLayer) {
-                auto error = (compositionInfo.hwc.hwcLayer)->
-                    setCompositionType(compositionInfo.compositionType);
-                ALOGE_IF(error != HWC2::Error::None,
-                        "[SF] Failed to set composition type: %s (%d)",
-                            to_string(error).c_str(), static_cast<int32_t>(error));
-            }
-            break;
-
-        case HWC2::Composition::Sideband:
-            configureHwcCommonData(compositionInfo);
-            configureSidebandComposition(compositionInfo);
-            break;
-
-        case HWC2::Composition::SolidColor:
-            configureHwcCommonData(compositionInfo);
-            break;
-
-        case HWC2::Composition::Device:
-        case HWC2::Composition::Cursor:
-            configureHwcCommonData(compositionInfo);
-            configureDeviceComposition(compositionInfo);
-            break;
-    }
-}
-
 void SurfaceFlinger::doComposition(const sp<DisplayDevice>& display, bool repaintEverything) {
     ATRACE_CALL();
     ALOGV("doComposition");
@@ -2325,14 +2173,15 @@
         }
         display->onSwapBuffersCompleted();
         display->makeCurrent();
-        for (auto& compositionInfo : getBE().mCompositionInfo[displayId]) {
+        for (auto& layer : display->getVisibleLayersSortedByZ()) {
             sp<Fence> releaseFence = Fence::NO_FENCE;
+
             // The layer buffer from the previous frame (if any) is released
             // by HWC only when the release fence from this frame (if any) is
             // signaled.  Always get the release fence from HWC first.
-            auto hwcLayer = compositionInfo.hwc.hwcLayer;
-            if ((displayId >= 0) && hwcLayer) {
-                releaseFence = getBE().mHwc->getLayerReleaseFence(displayId, hwcLayer.get());
+            auto hwcLayer = layer->getHwcLayer(displayId);
+            if (displayId >= 0) {
+                releaseFence = getBE().mHwc->getLayerReleaseFence(displayId, hwcLayer);
             }
 
             // If the layer was client composited in the previous frame, we
@@ -2340,14 +2189,12 @@
             // Since we do not track that, always merge with the current
             // client target acquire fence when it is available, even though
             // this is suboptimal.
-            if (compositionInfo.compositionType == HWC2::Composition::Client) {
+            if (layer->getCompositionType(displayId) == HWC2::Composition::Client) {
                 releaseFence = Fence::merge("LayerRelease", releaseFence,
                                             display->getClientTargetAcquireFence());
             }
 
-            if (compositionInfo.layer) {
-                compositionInfo.layer->onLayerDisplayed(releaseFence);
-            }
+            layer->getBE().onLayerDisplayed(releaseFence);
         }
 
         // We've got a list of layers needing fences, that are disjoint with
@@ -4135,6 +3982,10 @@
         getHwComposer().setPowerMode(type, mode);
     }
 
+    if (display->isPrimary()) {
+        mTimeStats.setPowerMode(mode);
+    }
+
     ALOGD("Finished setting power mode %d on display %d", mode, displayId);
 }
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index f535c4e..658f04e 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -689,7 +689,6 @@
      * to prepare the hardware composer
      */
     void prepareFrame(const sp<DisplayDevice>& display);
-    void setUpHWComposer(const CompositionInfo& compositionInfo);
     void doComposition(const sp<DisplayDevice>& display, bool repainEverything);
     void doDebugFlashRegions(const sp<DisplayDevice>& display, bool repaintEverything);
     void doTracing(const char* where);
@@ -806,11 +805,6 @@
 
     std::atomic<bool> mRepaintEverything{false};
 
-    // helper methods
-    void configureHwcCommonData(const CompositionInfo& compositionInfo) const;
-    void configureDeviceComposition(const CompositionInfo& compositionInfo) const;
-    void configureSidebandComposition(const CompositionInfo& compositionInfo) const;
-
     // constant members (no synchronization needed for access)
     nsecs_t mBootTime;
     bool mGpuToCpuSupported;
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index 2e1231b..43fa262 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -24,6 +24,7 @@
 #include <log/log.h>
 
 #include <utils/String8.h>
+#include <utils/Timers.h>
 #include <utils/Trace.h>
 
 #include <algorithm>
@@ -82,7 +83,7 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    timeStats.totalFrames++;
+    mTimeStats.totalFrames++;
 }
 
 void TimeStats::incrementMissedFrames() {
@@ -91,7 +92,7 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    timeStats.missedFrames++;
+    mTimeStats.missedFrames++;
 }
 
 void TimeStats::incrementClientCompositionFrames() {
@@ -100,12 +101,12 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    timeStats.clientCompositionFrames++;
+    mTimeStats.clientCompositionFrames++;
 }
 
-bool TimeStats::recordReadyLocked(const std::string& layerName, TimeRecord* timeRecord) {
+bool TimeStats::recordReadyLocked(int32_t layerID, TimeRecord* timeRecord) {
     if (!timeRecord->ready) {
-        ALOGV("[%s]-[%" PRIu64 "]-presentFence is still not received", layerName.c_str(),
+        ALOGV("[%d]-[%" PRIu64 "]-presentFence is still not received", layerID,
               timeRecord->frameTime.frameNumber);
         return false;
     }
@@ -118,7 +119,7 @@
             timeRecord->frameTime.acquireTime = timeRecord->acquireFence->getSignalTime();
             timeRecord->acquireFence = nullptr;
         } else {
-            ALOGV("[%s]-[%" PRIu64 "]-acquireFence signal time is invalid", layerName.c_str(),
+            ALOGV("[%d]-[%" PRIu64 "]-acquireFence signal time is invalid", layerID,
                   timeRecord->frameTime.frameNumber);
         }
     }
@@ -131,7 +132,7 @@
             timeRecord->frameTime.presentTime = timeRecord->presentFence->getSignalTime();
             timeRecord->presentFence = nullptr;
         } else {
-            ALOGV("[%s]-[%" PRIu64 "]-presentFence signal time invalid", layerName.c_str(),
+            ALOGV("[%d]-[%" PRIu64 "]-presentFence signal time invalid", layerID,
                   timeRecord->frameTime.frameNumber);
         }
     }
@@ -161,60 +162,61 @@
     return "";
 }
 
-void TimeStats::flushAvailableRecordsToStatsLocked(const std::string& layerName) {
+void TimeStats::flushAvailableRecordsToStatsLocked(int32_t layerID) {
     ATRACE_CALL();
 
-    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    LayerRecord& layerRecord = mTimeStatsTracker[layerID];
     TimeRecord& prevTimeRecord = layerRecord.prevTimeRecord;
     std::deque<TimeRecord>& timeRecords = layerRecord.timeRecords;
     while (!timeRecords.empty()) {
-        if (!recordReadyLocked(layerName, &timeRecords[0])) break;
-        ALOGV("[%s]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerName.c_str(),
+        if (!recordReadyLocked(layerID, &timeRecords[0])) break;
+        ALOGV("[%d]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerID,
               timeRecords[0].frameTime.frameNumber, timeRecords[0].frameTime.presentTime);
 
         if (prevTimeRecord.ready) {
-            if (!timeStats.stats.count(layerName)) {
-                timeStats.stats[layerName].layerName = layerName;
-                timeStats.stats[layerName].packageName = getPackageName(layerName);
+            const std::string& layerName = layerRecord.layerName;
+            if (!mTimeStats.stats.count(layerName)) {
+                mTimeStats.stats[layerName].layerName = layerName;
+                mTimeStats.stats[layerName].packageName = getPackageName(layerName);
             }
-            TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timeStats.stats[layerName];
+            TimeStatsHelper::TimeStatsLayer& timeStatsLayer = mTimeStats.stats[layerName];
             timeStatsLayer.totalFrames++;
             timeStatsLayer.droppedFrames += layerRecord.droppedFrames;
             layerRecord.droppedFrames = 0;
 
             const int32_t postToAcquireMs = msBetween(timeRecords[0].frameTime.postTime,
                                                       timeRecords[0].frameTime.acquireTime);
-            ALOGV("[%s]-[%" PRIu64 "]-post2acquire[%d]", layerName.c_str(),
+            ALOGV("[%d]-[%" PRIu64 "]-post2acquire[%d]", layerID,
                   timeRecords[0].frameTime.frameNumber, postToAcquireMs);
             timeStatsLayer.deltas["post2acquire"].insert(postToAcquireMs);
 
             const int32_t postToPresentMs = msBetween(timeRecords[0].frameTime.postTime,
                                                       timeRecords[0].frameTime.presentTime);
-            ALOGV("[%s]-[%" PRIu64 "]-post2present[%d]", layerName.c_str(),
+            ALOGV("[%d]-[%" PRIu64 "]-post2present[%d]", layerID,
                   timeRecords[0].frameTime.frameNumber, postToPresentMs);
             timeStatsLayer.deltas["post2present"].insert(postToPresentMs);
 
             const int32_t acquireToPresentMs = msBetween(timeRecords[0].frameTime.acquireTime,
                                                          timeRecords[0].frameTime.presentTime);
-            ALOGV("[%s]-[%" PRIu64 "]-acquire2present[%d]", layerName.c_str(),
+            ALOGV("[%d]-[%" PRIu64 "]-acquire2present[%d]", layerID,
                   timeRecords[0].frameTime.frameNumber, acquireToPresentMs);
             timeStatsLayer.deltas["acquire2present"].insert(acquireToPresentMs);
 
             const int32_t latchToPresentMs = msBetween(timeRecords[0].frameTime.latchTime,
                                                        timeRecords[0].frameTime.presentTime);
-            ALOGV("[%s]-[%" PRIu64 "]-latch2present[%d]", layerName.c_str(),
+            ALOGV("[%d]-[%" PRIu64 "]-latch2present[%d]", layerID,
                   timeRecords[0].frameTime.frameNumber, latchToPresentMs);
             timeStatsLayer.deltas["latch2present"].insert(latchToPresentMs);
 
             const int32_t desiredToPresentMs = msBetween(timeRecords[0].frameTime.desiredTime,
                                                          timeRecords[0].frameTime.presentTime);
-            ALOGV("[%s]-[%" PRIu64 "]-desired2present[%d]", layerName.c_str(),
+            ALOGV("[%d]-[%" PRIu64 "]-desired2present[%d]", layerID,
                   timeRecords[0].frameTime.frameNumber, desiredToPresentMs);
             timeStatsLayer.deltas["desired2present"].insert(desiredToPresentMs);
 
             const int32_t presentToPresentMs = msBetween(prevTimeRecord.frameTime.presentTime,
                                                          timeRecords[0].frameTime.presentTime);
-            ALOGV("[%s]-[%" PRIu64 "]-present2present[%d]", layerName.c_str(),
+            ALOGV("[%d]-[%" PRIu64 "]-present2present[%d]", layerID,
                   timeRecords[0].frameTime.frameNumber, presentToPresentMs);
             timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
         }
@@ -239,23 +241,33 @@
     return std::regex_match(layerName.begin(), layerName.end(), layerNameRegex);
 }
 
-void TimeStats::setPostTime(const std::string& layerName, uint64_t frameNumber, nsecs_t postTime) {
+void TimeStats::setLayerName(int32_t layerID, const std::string& layerName) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
-    ALOGV("[%s]-[%" PRIu64 "]-PostTime[%" PRId64 "]", layerName.c_str(), frameNumber, postTime);
+    ALOGV("[%d]-[%s]", layerID, layerName.c_str());
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (!timeStatsTracker.count(layerName) && !layerNameIsValid(layerName)) {
-        return;
+    if (!mTimeStatsTracker.count(layerID) && layerNameIsValid(layerName)) {
+        mTimeStatsTracker[layerID].layerName = layerName;
     }
-    LayerRecord& layerRecord = timeStatsTracker[layerName];
+}
+
+void TimeStats::setPostTime(int32_t layerID, uint64_t frameNumber, nsecs_t postTime) {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+    ALOGV("[%d]-[%" PRIu64 "]-PostTime[%" PRId64 "]", layerID, frameNumber, postTime);
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!mTimeStatsTracker.count(layerID)) return;
+    LayerRecord& layerRecord = mTimeStatsTracker[layerID];
     if (layerRecord.timeRecords.size() == MAX_NUM_TIME_RECORDS) {
-        ALOGV("[%s]-timeRecords is already at its maximum size[%zu]", layerName.c_str(),
-              MAX_NUM_TIME_RECORDS);
-        // TODO(zzyiwei): if this happens, there must be a present fence missing
-        // or waitData is not in the correct position. Need to think out a
-        // reasonable way to recover from this state.
+        ALOGE("[%d]-[%s]-timeRecords is already at its maximum size[%zu]. Please file a bug.",
+              layerID, layerRecord.layerName.c_str(), MAX_NUM_TIME_RECORDS);
+        layerRecord.timeRecords.clear();
+        layerRecord.prevTimeRecord.ready = false;
+        layerRecord.waitData = -1;
         return;
     }
     // For most media content, the acquireFence is invalid because the buffer is
@@ -275,84 +287,77 @@
         layerRecord.waitData = layerRecord.timeRecords.size() - 1;
 }
 
-void TimeStats::setLatchTime(const std::string& layerName, uint64_t frameNumber,
-                             nsecs_t latchTime) {
+void TimeStats::setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
-    ALOGV("[%s]-[%" PRIu64 "]-LatchTime[%" PRId64 "]", layerName.c_str(), frameNumber, latchTime);
+    ALOGV("[%d]-[%" PRIu64 "]-LatchTime[%" PRId64 "]", layerID, frameNumber, latchTime);
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (!timeStatsTracker.count(layerName)) return;
-    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    if (!mTimeStatsTracker.count(layerID)) return;
+    LayerRecord& layerRecord = mTimeStatsTracker[layerID];
     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
     if (timeRecord.frameTime.frameNumber == frameNumber) {
         timeRecord.frameTime.latchTime = latchTime;
     }
 }
 
-void TimeStats::setDesiredTime(const std::string& layerName, uint64_t frameNumber,
-                               nsecs_t desiredTime) {
+void TimeStats::setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
-    ALOGV("[%s]-[%" PRIu64 "]-DesiredTime[%" PRId64 "]", layerName.c_str(), frameNumber,
-          desiredTime);
+    ALOGV("[%d]-[%" PRIu64 "]-DesiredTime[%" PRId64 "]", layerID, frameNumber, desiredTime);
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (!timeStatsTracker.count(layerName)) return;
-    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    if (!mTimeStatsTracker.count(layerID)) return;
+    LayerRecord& layerRecord = mTimeStatsTracker[layerID];
     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
     if (timeRecord.frameTime.frameNumber == frameNumber) {
         timeRecord.frameTime.desiredTime = desiredTime;
     }
 }
 
-void TimeStats::setAcquireTime(const std::string& layerName, uint64_t frameNumber,
-                               nsecs_t acquireTime) {
+void TimeStats::setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
-    ALOGV("[%s]-[%" PRIu64 "]-AcquireTime[%" PRId64 "]", layerName.c_str(), frameNumber,
-          acquireTime);
+    ALOGV("[%d]-[%" PRIu64 "]-AcquireTime[%" PRId64 "]", layerID, frameNumber, acquireTime);
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (!timeStatsTracker.count(layerName)) return;
-    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    if (!mTimeStatsTracker.count(layerID)) return;
+    LayerRecord& layerRecord = mTimeStatsTracker[layerID];
     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
     if (timeRecord.frameTime.frameNumber == frameNumber) {
         timeRecord.frameTime.acquireTime = acquireTime;
     }
 }
 
-void TimeStats::setAcquireFence(const std::string& layerName, uint64_t frameNumber,
+void TimeStats::setAcquireFence(int32_t layerID, uint64_t frameNumber,
                                 const std::shared_ptr<FenceTime>& acquireFence) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
-    ALOGV("[%s]-[%" PRIu64 "]-AcquireFenceTime[%" PRId64 "]", layerName.c_str(), frameNumber,
+    ALOGV("[%d]-[%" PRIu64 "]-AcquireFenceTime[%" PRId64 "]", layerID, frameNumber,
           acquireFence->getSignalTime());
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (!timeStatsTracker.count(layerName)) return;
-    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    if (!mTimeStatsTracker.count(layerID)) return;
+    LayerRecord& layerRecord = mTimeStatsTracker[layerID];
     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
     if (timeRecord.frameTime.frameNumber == frameNumber) {
         timeRecord.acquireFence = acquireFence;
     }
 }
 
-void TimeStats::setPresentTime(const std::string& layerName, uint64_t frameNumber,
-                               nsecs_t presentTime) {
+void TimeStats::setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
-    ALOGV("[%s]-[%" PRIu64 "]-PresentTime[%" PRId64 "]", layerName.c_str(), frameNumber,
-          presentTime);
+    ALOGV("[%d]-[%" PRIu64 "]-PresentTime[%" PRId64 "]", layerID, frameNumber, presentTime);
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (!timeStatsTracker.count(layerName)) return;
-    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    if (!mTimeStatsTracker.count(layerID)) return;
+    LayerRecord& layerRecord = mTimeStatsTracker[layerID];
     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
     if (timeRecord.frameTime.frameNumber == frameNumber) {
         timeRecord.frameTime.presentTime = presentTime;
@@ -360,20 +365,20 @@
         layerRecord.waitData++;
     }
 
-    flushAvailableRecordsToStatsLocked(layerName);
+    flushAvailableRecordsToStatsLocked(layerID);
 }
 
-void TimeStats::setPresentFence(const std::string& layerName, uint64_t frameNumber,
+void TimeStats::setPresentFence(int32_t layerID, uint64_t frameNumber,
                                 const std::shared_ptr<FenceTime>& presentFence) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
-    ALOGV("[%s]-[%" PRIu64 "]-PresentFenceTime[%" PRId64 "]", layerName.c_str(), frameNumber,
+    ALOGV("[%d]-[%" PRIu64 "]-PresentFenceTime[%" PRId64 "]", layerID, frameNumber,
           presentFence->getSignalTime());
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (!timeStatsTracker.count(layerName)) return;
-    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    if (!mTimeStatsTracker.count(layerID)) return;
+    LayerRecord& layerRecord = mTimeStatsTracker[layerID];
     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
     if (timeRecord.frameTime.frameNumber == frameNumber) {
         timeRecord.presentFence = presentFence;
@@ -381,45 +386,57 @@
         layerRecord.waitData++;
     }
 
-    flushAvailableRecordsToStatsLocked(layerName);
+    flushAvailableRecordsToStatsLocked(layerID);
 }
 
-void TimeStats::onDisconnect(const std::string& layerName) {
+void TimeStats::onDisconnect(int32_t layerID) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
-    ALOGV("[%s]-onDisconnect", layerName.c_str());
+    ALOGV("[%d]-onDisconnect", layerID);
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (!timeStatsTracker.count(layerName)) return;
-    flushAvailableRecordsToStatsLocked(layerName);
-    timeStatsTracker.erase(layerName);
+    if (!mTimeStatsTracker.count(layerID)) return;
+    flushAvailableRecordsToStatsLocked(layerID);
+    mTimeStatsTracker.erase(layerID);
 }
 
-void TimeStats::clearLayerRecord(const std::string& layerName) {
+void TimeStats::onDestroy(int32_t layerID) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
-    ALOGV("[%s]-clearLayerRecord", layerName.c_str());
+    ALOGV("[%d]-onDestroy", layerID);
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (!timeStatsTracker.count(layerName)) return;
-    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    if (!mTimeStatsTracker.count(layerID)) return;
+    flushAvailableRecordsToStatsLocked(layerID);
+    mTimeStatsTracker.erase(layerID);
+}
+
+void TimeStats::clearLayerRecord(int32_t layerID) {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+    ALOGV("[%d]-clearLayerRecord", layerID);
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!mTimeStatsTracker.count(layerID)) return;
+    LayerRecord& layerRecord = mTimeStatsTracker[layerID];
     layerRecord.timeRecords.clear();
     layerRecord.prevTimeRecord.ready = false;
     layerRecord.waitData = -1;
     layerRecord.droppedFrames = 0;
 }
 
-void TimeStats::removeTimeRecord(const std::string& layerName, uint64_t frameNumber) {
+void TimeStats::removeTimeRecord(int32_t layerID, uint64_t frameNumber) {
     if (!mEnabled.load()) return;
 
     ATRACE_CALL();
-    ALOGV("[%s]-[%" PRIu64 "]-removeTimeRecord", layerName.c_str(), frameNumber);
+    ALOGV("[%d]-[%" PRIu64 "]-removeTimeRecord", layerID, frameNumber);
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (!timeStatsTracker.count(layerName)) return;
-    LayerRecord& layerRecord = timeStatsTracker[layerName];
+    if (!mTimeStatsTracker.count(layerID)) return;
+    LayerRecord& layerRecord = mTimeStatsTracker[layerID];
     size_t removeAt = 0;
     for (const TimeRecord& record : layerRecord.timeRecords) {
         if (record.frameTime.frameNumber == frameNumber) break;
@@ -433,6 +450,87 @@
     layerRecord.droppedFrames++;
 }
 
+void TimeStats::flushPowerTimeLocked() {
+    nsecs_t curTime = systemTime();
+    // elapsedTime is in milliseconds.
+    int64_t elapsedTime = (curTime - mPowerTime.prevTime) / 1000000;
+
+    switch (mPowerTime.powerMode) {
+        case HWC_POWER_MODE_NORMAL:
+            mTimeStats.displayOnTime += elapsedTime;
+            break;
+        case HWC_POWER_MODE_OFF:
+        case HWC_POWER_MODE_DOZE:
+        case HWC_POWER_MODE_DOZE_SUSPEND:
+        default:
+            break;
+    }
+
+    mPowerTime.prevTime = curTime;
+}
+
+void TimeStats::setPowerMode(int32_t powerMode) {
+    if (!mEnabled.load()) {
+        std::lock_guard<std::mutex> lock(mMutex);
+        mPowerTime.powerMode = powerMode;
+        return;
+    }
+
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (powerMode == mPowerTime.powerMode) return;
+
+    flushPowerTimeLocked();
+    mPowerTime.powerMode = powerMode;
+}
+
+void TimeStats::flushAvailableGlobalRecordsToStatsLocked() {
+    ATRACE_CALL();
+
+    while (!mGlobalRecord.presentFences.empty()) {
+        const nsecs_t curPresentTime = mGlobalRecord.presentFences.front()->getSignalTime();
+        if (curPresentTime == Fence::SIGNAL_TIME_PENDING) break;
+
+        if (curPresentTime == Fence::SIGNAL_TIME_INVALID) {
+            ALOGE("GlobalPresentFence is invalid!");
+            mGlobalRecord.prevPresentTime = 0;
+            mGlobalRecord.presentFences.pop_front();
+            continue;
+        }
+
+        ALOGV("GlobalPresentFenceTime[%" PRId64 "]",
+              mGlobalRecord.presentFences.front()->getSignalTime());
+
+        const int32_t presentToPresentMs = msBetween(mGlobalRecord.prevPresentTime, curPresentTime);
+        ALOGV("Global present2present[%d]", presentToPresentMs);
+
+        mTimeStats.presentToPresent.insert(presentToPresentMs);
+        mGlobalRecord.prevPresentTime = curPresentTime;
+        mGlobalRecord.presentFences.pop_front();
+    }
+}
+
+void TimeStats::setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence) {
+    if (!mEnabled.load()) return;
+
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (presentFence == nullptr) {
+        mGlobalRecord.prevPresentTime = 0;
+        return;
+    }
+
+    if (mGlobalRecord.presentFences.size() == MAX_NUM_TIME_RECORDS) {
+        // The front presentFence must be trapped in pending status in this
+        // case. Try dequeuing the front one to recover.
+        ALOGE("GlobalPresentFences is already at its maximum size[%zu]", MAX_NUM_TIME_RECORDS);
+        mGlobalRecord.prevPresentTime = 0;
+        mGlobalRecord.presentFences.pop_front();
+    }
+
+    mGlobalRecord.presentFences.emplace_back(presentFence);
+    flushAvailableGlobalRecordsToStatsLocked();
+}
+
 void TimeStats::enable() {
     if (mEnabled.load()) return;
 
@@ -441,7 +539,8 @@
     std::lock_guard<std::mutex> lock(mMutex);
     ALOGD("Enabled");
     mEnabled.store(true);
-    timeStats.statsStart = static_cast<int64_t>(std::time(0));
+    mTimeStats.statsStart = static_cast<int64_t>(std::time(0));
+    mPowerTime.prevTime = systemTime();
 }
 
 void TimeStats::disable() {
@@ -452,7 +551,7 @@
     std::lock_guard<std::mutex> lock(mMutex);
     ALOGD("Disabled");
     mEnabled.store(false);
-    timeStats.statsEnd = static_cast<int64_t>(std::time(0));
+    mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
 }
 
 void TimeStats::clear() {
@@ -460,12 +559,15 @@
 
     std::lock_guard<std::mutex> lock(mMutex);
     ALOGD("Cleared");
-    timeStats.stats.clear();
-    timeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
-    timeStats.statsEnd = 0;
-    timeStats.totalFrames = 0;
-    timeStats.missedFrames = 0;
-    timeStats.clientCompositionFrames = 0;
+    mTimeStats.stats.clear();
+    mTimeStats.statsStart = (mEnabled.load() ? static_cast<int64_t>(std::time(0)) : 0);
+    mTimeStats.statsEnd = 0;
+    mTimeStats.totalFrames = 0;
+    mTimeStats.missedFrames = 0;
+    mTimeStats.clientCompositionFrames = 0;
+    mTimeStats.displayOnTime = 0;
+    mTimeStats.presentToPresent.hist.clear();
+    mPowerTime.prevTime = systemTime();
 }
 
 bool TimeStats::isEnabled() {
@@ -476,19 +578,21 @@
     ATRACE_CALL();
 
     std::lock_guard<std::mutex> lock(mMutex);
-    if (timeStats.statsStart == 0) {
+    if (mTimeStats.statsStart == 0) {
         return;
     }
 
-    timeStats.statsEnd = static_cast<int64_t>(std::time(0));
+    mTimeStats.statsEnd = static_cast<int64_t>(std::time(0));
+
+    flushPowerTimeLocked();
 
     if (asProto) {
         ALOGD("Dumping TimeStats as proto");
-        SFTimeStatsGlobalProto timeStatsProto = timeStats.toProto(maxLayers);
+        SFTimeStatsGlobalProto timeStatsProto = mTimeStats.toProto(maxLayers);
         result.append(timeStatsProto.SerializeAsString().c_str(), timeStatsProto.ByteSize());
     } else {
         ALOGD("Dumping TimeStats as text");
-        result.append(timeStats.toString(maxLayers).c_str());
+        result.append(mTimeStats.toString(maxLayers).c_str());
         result.append("\n");
     }
 }
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 5ab3934..d1e554c 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -19,6 +19,8 @@
 #include <timestatsproto/TimeStatsHelper.h>
 #include <timestatsproto/TimeStatsProtoHeader.h>
 
+#include <hardware/hwcomposer_defs.h>
+
 #include <ui/FenceTime.h>
 
 #include <utils/String16.h>
@@ -57,6 +59,7 @@
     };
 
     struct LayerRecord {
+        std::string layerName;
         // This is the index in timeRecords, at which the timestamps for that
         // specific frame are still not fully received. This is not waiting for
         // fences to signal, but rather waiting to receive those fences/timestamps.
@@ -66,6 +69,16 @@
         std::deque<TimeRecord> timeRecords;
     };
 
+    struct PowerTime {
+        int32_t powerMode = HWC_POWER_MODE_OFF;
+        nsecs_t prevTime = 0;
+    };
+
+    struct GlobalRecord {
+        nsecs_t prevPresentTime = 0;
+        std::deque<std::shared_ptr<FenceTime>> presentFences;
+    };
+
 public:
     static TimeStats& getInstance();
     void parseArgs(bool asProto, const Vector<String16>& args, size_t& index, String8& result);
@@ -73,27 +86,35 @@
     void incrementMissedFrames();
     void incrementClientCompositionFrames();
 
-    void setPostTime(const std::string& layerName, uint64_t frameNumber, nsecs_t postTime);
-    void setLatchTime(const std::string& layerName, uint64_t frameNumber, nsecs_t latchTime);
-    void setDesiredTime(const std::string& layerName, uint64_t frameNumber, nsecs_t desiredTime);
-    void setAcquireTime(const std::string& layerName, uint64_t frameNumber, nsecs_t acquireTime);
-    void setAcquireFence(const std::string& layerName, uint64_t frameNumber,
+    void setLayerName(int32_t layerID, const std::string& layerName);
+    void setPostTime(int32_t layerID, uint64_t frameNumber, nsecs_t postTime);
+    void setLatchTime(int32_t layerID, uint64_t frameNumber, nsecs_t latchTime);
+    void setDesiredTime(int32_t layerID, uint64_t frameNumber, nsecs_t desiredTime);
+    void setAcquireTime(int32_t layerID, uint64_t frameNumber, nsecs_t acquireTime);
+    void setAcquireFence(int32_t layerID, uint64_t frameNumber,
                          const std::shared_ptr<FenceTime>& acquireFence);
-    void setPresentTime(const std::string& layerName, uint64_t frameNumber, nsecs_t presentTime);
-    void setPresentFence(const std::string& layerName, uint64_t frameNumber,
+    void setPresentTime(int32_t layerID, uint64_t frameNumber, nsecs_t presentTime);
+    void setPresentFence(int32_t layerID, uint64_t frameNumber,
                          const std::shared_ptr<FenceTime>& presentFence);
     // On producer disconnect with BufferQueue.
-    void onDisconnect(const std::string& layerName);
+    void onDisconnect(int32_t layerID);
+    // On layer tear down.
+    void onDestroy(int32_t layerID);
     // When SF is cleaning up the queue, clear the LayerRecord as well.
-    void clearLayerRecord(const std::string& layerName);
+    void clearLayerRecord(int32_t layerID);
     // If SF skips or rejects a buffer, remove the corresponding TimeRecord.
-    void removeTimeRecord(const std::string& layerName, uint64_t frameNumber);
+    void removeTimeRecord(int32_t layerID, uint64_t frameNumber);
+
+    void setPowerMode(int32_t powerMode);
+    void setPresentFenceGlobal(const std::shared_ptr<FenceTime>& presentFence);
 
 private:
     TimeStats() = default;
 
-    bool recordReadyLocked(const std::string& layerName, TimeRecord* timeRecord);
-    void flushAvailableRecordsToStatsLocked(const std::string& layerName);
+    bool recordReadyLocked(int32_t layerID, TimeRecord* timeRecord);
+    void flushAvailableRecordsToStatsLocked(int32_t layerID);
+    void flushPowerTimeLocked();
+    void flushAvailableGlobalRecordsToStatsLocked();
 
     void enable();
     void disable();
@@ -103,8 +124,11 @@
 
     std::atomic<bool> mEnabled = false;
     std::mutex mMutex;
-    TimeStatsHelper::TimeStatsGlobal timeStats;
-    std::unordered_map<std::string, LayerRecord> timeStatsTracker;
+    TimeStatsHelper::TimeStatsGlobal mTimeStats;
+    // Hashmap for LayerRecord with layerID as the hash key
+    std::unordered_map<int32_t, LayerRecord> mTimeStatsTracker;
+    PowerTime mPowerTime;
+    GlobalRecord mGlobalRecord;
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index b7b2778..c701224 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -49,7 +49,7 @@
 float TimeStatsHelper::Histogram::averageTime() const {
     int64_t ret = 0;
     int64_t count = 0;
-    for (auto& ele : hist) {
+    for (const auto& ele : hist) {
         count += ele.second;
         ret += ele.first * ele.second;
     }
@@ -73,13 +73,13 @@
     StringAppendF(&result, "packageName = %s\n", packageName.c_str());
     StringAppendF(&result, "totalFrames = %d\n", totalFrames);
     StringAppendF(&result, "droppedFrames = %d\n", droppedFrames);
-    auto iter = deltas.find("present2present");
+    const auto iter = deltas.find("present2present");
     if (iter != deltas.end()) {
         StringAppendF(&result, "averageFPS = %.3f\n", 1000.0 / iter->second.averageTime());
     }
-    for (auto& ele : deltas) {
+    for (const auto& ele : deltas) {
         StringAppendF(&result, "%s histogram is as below:\n", ele.first.c_str());
-        StringAppendF(&result, "%s", ele.second.toString().c_str());
+        result.append(ele.second.toString());
     }
 
     return result;
@@ -92,9 +92,12 @@
     StringAppendF(&result, "totalFrames = %d\n", totalFrames);
     StringAppendF(&result, "missedFrames = %d\n", missedFrames);
     StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
+    StringAppendF(&result, "displayOnTime = %lld ms\n", static_cast<long long int>(displayOnTime));
+    StringAppendF(&result, "presentToPresent histogram is as below:\n");
+    result.append(presentToPresent.toString());
     const auto dumpStats = generateDumpStats(maxLayers);
-    for (auto& ele : dumpStats) {
-        StringAppendF(&result, "%s", ele->toString().c_str());
+    for (const auto& ele : dumpStats) {
+        result.append(ele->toString());
     }
 
     return result;
@@ -106,10 +109,10 @@
     layerProto.set_package_name(packageName);
     layerProto.set_total_frames(totalFrames);
     layerProto.set_dropped_frames(droppedFrames);
-    for (auto& ele : deltas) {
+    for (const auto& ele : deltas) {
         SFTimeStatsDeltaProto* deltaProto = layerProto.add_deltas();
         deltaProto->set_delta_name(ele.first);
-        for (auto& histEle : ele.second.hist) {
+        for (const auto& histEle : ele.second.hist) {
             SFTimeStatsHistogramBucketProto* histProto = deltaProto->add_histograms();
             histProto->set_time_millis(histEle.first);
             histProto->set_frame_count(histEle.second);
@@ -126,8 +129,14 @@
     globalProto.set_total_frames(totalFrames);
     globalProto.set_missed_frames(missedFrames);
     globalProto.set_client_composition_frames(clientCompositionFrames);
+    globalProto.set_display_on_time(displayOnTime);
+    for (const auto& histEle : presentToPresent.hist) {
+        SFTimeStatsHistogramBucketProto* histProto = globalProto.add_present_to_present();
+        histProto->set_time_millis(histEle.first);
+        histProto->set_frame_count(histEle.second);
+    }
     const auto dumpStats = generateDumpStats(maxLayers);
-    for (auto& ele : dumpStats) {
+    for (const auto& ele : dumpStats) {
         SFTimeStatsLayerProto* layerProto = globalProto.add_stats();
         layerProto->CopyFrom(ele->toProto());
     }
@@ -137,7 +146,7 @@
 std::vector<TimeStatsHelper::TimeStatsLayer const*>
 TimeStatsHelper::TimeStatsGlobal::generateDumpStats(std::optional<uint32_t> maxLayers) const {
     std::vector<TimeStatsLayer const*> dumpStats;
-    for (auto& ele : stats) {
+    for (const auto& ele : stats) {
         dumpStats.push_back(&ele.second);
     }
 
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 99c891b..7d0fe79 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -57,6 +57,8 @@
         int32_t totalFrames = 0;
         int32_t missedFrames = 0;
         int32_t clientCompositionFrames = 0;
+        int64_t displayOnTime = 0;
+        Histogram presentToPresent;
         std::unordered_map<std::string, TimeStatsLayer> stats;
 
         std::string toString(std::optional<uint32_t> maxLayers) const;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
index b8f38c2..377612a 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
+++ b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
@@ -20,13 +20,12 @@
 
 option optimize_for = LITE_RUNTIME;
 
-// //depot/google3/java/com/google/android/apps/graphics/stats/proto/
+// //depot/google3/wireless/android/graphics/surfaceflingerstats/proto/
 // timestats.proto is based on this proto. Please only make valid protobuf
-// changes to these messages, and keep the other file in sync per Android
-// release. Please also do not include "option optimize_for = LITE_RUNTIME;" at
-// google3 side.
+// changes to these messages, and keep google3 side proto messages in sync if
+// the end to end pipeline needs to be updated.
 
-// Next tag: 7
+// Next tag: 9
 message SFTimeStatsGlobalProto {
   // The stats start time in UTC as seconds since January 1, 1970
   optional int64 stats_start = 1;
@@ -38,6 +37,10 @@
   optional int32 missed_frames = 4;
   // Total frames fallback to client composition.
   optional int32 client_composition_frames = 5;
+  // Primary display on time in milliseconds.
+  optional int64 display_on_time = 7;
+  // Present to present histogram.
+  repeated SFTimeStatsHistogramBucketProto present_to_present = 8;
   // Stats per layer. Apps could have multiple layers.
   repeated SFTimeStatsLayerProto stats = 6;
 }
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 4e403b7..3719a3d 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -42,6 +42,7 @@
 namespace {
 
 using testing::_;
+using testing::AtLeast;
 using testing::ByMove;
 using testing::DoAll;
 using testing::IsNull;
@@ -514,7 +515,7 @@
         // expectations are for appears to make an extra call to them.
         // TODO: Investigate this extra call
         EXPECT_CALL(*test->mComposer, setLayerTransform(HWC_DISPLAY, HWC_LAYER, DEFAULT_TRANSFORM))
-                .Times(1)
+                .Times(AtLeast(1))
                 .RetiresOnSaturation();
     }
 
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index b474e42..d32627a 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -22,6 +22,7 @@
 
 #include <log/log.h>
 
+#include <ui/DebugUtils.h>
 #include "TestableSurfaceFlinger.h"
 #include "mock/DisplayHardware/MockComposer.h"
 #include "mock/DisplayHardware/MockDisplaySurface.h"
@@ -997,6 +998,93 @@
 }
 
 /* ------------------------------------------------------------------------
+ * DisplayDevice::GetBestColorMode
+ */
+class GetBestColorModeTest : public DisplayTransactionTest {
+public:
+    GetBestColorModeTest()
+          : DisplayTransactionTest(),
+            mInjector(FakeDisplayDeviceInjector(mFlinger, DisplayDevice::DISPLAY_PRIMARY, 0)) {}
+
+    void setHasWideColorGamut(bool hasWideColorGamut) { mHasWideColorGamut = hasWideColorGamut; }
+
+    void addHwcColorModesMapping(ui::ColorMode colorMode,
+                                 std::vector<ui::RenderIntent> renderIntents) {
+        mHwcColorModes[colorMode] = renderIntents;
+    }
+
+    void setInputDataspace(ui::Dataspace dataspace) { mInputDataspace = dataspace; }
+
+    void setInputRenderIntent(ui::RenderIntent renderIntent) { mInputRenderIntent = renderIntent; }
+
+    void getBestColorMode() {
+        mInjector.setHwcColorModes(mHwcColorModes);
+        mInjector.setHasWideColorGamut(mHasWideColorGamut);
+        auto displayDevice = mInjector.inject();
+
+        displayDevice->getBestColorMode(mInputDataspace, mInputRenderIntent, &mOutDataspace,
+                                        &mOutColorMode, &mOutRenderIntent);
+    }
+
+    ui::Dataspace mOutDataspace;
+    ui::ColorMode mOutColorMode;
+    ui::RenderIntent mOutRenderIntent;
+
+private:
+    ui::Dataspace mInputDataspace;
+    ui::RenderIntent mInputRenderIntent;
+    bool mHasWideColorGamut = false;
+    std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> mHwcColorModes;
+    FakeDisplayDeviceInjector mInjector;
+};
+
+TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeSRGB) {
+    addHwcColorModesMapping(ui::ColorMode::SRGB,
+                            std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+    setInputDataspace(ui::Dataspace::DISPLAY_P3);
+    setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
+    setHasWideColorGamut(true);
+
+    getBestColorMode();
+
+    ASSERT_EQ(ui::Dataspace::SRGB, mOutDataspace);
+    ASSERT_EQ(ui::ColorMode::SRGB, mOutColorMode);
+    ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
+}
+
+TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDisplayP3) {
+    addHwcColorModesMapping(ui::ColorMode::DISPLAY_P3,
+                            std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+    addHwcColorModesMapping(ui::ColorMode::SRGB,
+                            std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+    addHwcColorModesMapping(ui::ColorMode::DISPLAY_BT2020,
+                            std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+    setInputDataspace(ui::Dataspace::DISPLAY_P3);
+    setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
+    setHasWideColorGamut(true);
+
+    getBestColorMode();
+
+    ASSERT_EQ(ui::Dataspace::DISPLAY_P3, mOutDataspace);
+    ASSERT_EQ(ui::ColorMode::DISPLAY_P3, mOutColorMode);
+    ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
+}
+
+TEST_F(GetBestColorModeTest, DataspaceDisplayP3_ColorModeDISPLAY_BT2020) {
+    addHwcColorModesMapping(ui::ColorMode::DISPLAY_BT2020,
+                            std::vector<ui::RenderIntent>(1, RenderIntent::COLORIMETRIC));
+    setInputDataspace(ui::Dataspace::DISPLAY_P3);
+    setInputRenderIntent(ui::RenderIntent::COLORIMETRIC);
+    setHasWideColorGamut(true);
+
+    getBestColorMode();
+
+    ASSERT_EQ(ui::Dataspace::DISPLAY_BT2020, mOutDataspace);
+    ASSERT_EQ(ui::ColorMode::DISPLAY_BT2020, mOutColorMode);
+    ASSERT_EQ(ui::RenderIntent::COLORIMETRIC, mOutRenderIntent);
+}
+
+/* ------------------------------------------------------------------------
  * SurfaceFlinger::setupNewDisplayDeviceInternal
  */
 
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 2046439..62afde9 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -369,6 +369,18 @@
             return *this;
         }
 
+        auto& setHwcColorModes(
+                const std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>>
+                        hwcColorModes) {
+            mCreationArgs.hwcColorModes = hwcColorModes;
+            return *this;
+        }
+
+        auto& setHasWideColorGamut(bool hasWideColorGamut) {
+            mCreationArgs.hasWideColorGamut = hasWideColorGamut;
+            return *this;
+        }
+
         sp<DisplayDevice> inject() {
             DisplayDeviceState state;
             state.type = mCreationArgs.type;
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index ecf3181..c0395c0 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -30,10 +30,10 @@
 using android::hardware::graphics::common::V1_0::ColorTransform;
 using android::hardware::graphics::common::V1_0::Hdr;
 using android::hardware::graphics::common::V1_0::Transform;
-using android::hardware::graphics::common::V1_1::ColorMode;
-using android::hardware::graphics::common::V1_1::Dataspace;
 using android::hardware::graphics::common::V1_1::PixelFormat;
 using android::hardware::graphics::common::V1_1::RenderIntent;
+using android::hardware::graphics::common::V1_2::ColorMode;
+using android::hardware::graphics::common::V1_2::Dataspace;
 
 using android::hardware::graphics::composer::V2_1::Config;
 using android::hardware::graphics::composer::V2_1::Display;
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index 6813cda..afca63a 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -17,13 +17,15 @@
 #pragma once
 
 #include <gmock/gmock.h>
-
+#include <renderengine/DisplaySettings.h>
 #include <renderengine/Framebuffer.h>
 #include <renderengine/Image.h>
+#include <renderengine/LayerSettings.h>
 #include <renderengine/Mesh.h>
 #include <renderengine/RenderEngine.h>
 #include <renderengine/Surface.h>
 #include <renderengine/Texture.h>
+#include <ui/GraphicBuffer.h>
 
 namespace android {
 namespace renderengine {
@@ -75,6 +77,9 @@
     MOCK_METHOD1(drawMesh, void(const Mesh&));
     MOCK_CONST_METHOD0(getMaxTextureSize, size_t());
     MOCK_CONST_METHOD0(getMaxViewportDims, size_t());
+    MOCK_CONST_METHOD4(drawLayers,
+                       status_t(const DisplaySettings&, const std::vector<LayerSettings>&,
+                                ANativeWindowBuffer* const, base::unique_fd*));
 };
 
 class Surface : public renderengine::Surface {
diff --git a/services/vr/bufferhubd/IBufferHub.cpp b/services/vr/bufferhubd/IBufferHub.cpp
index 9d5b91a..2f39e41 100644
--- a/services/vr/bufferhubd/IBufferHub.cpp
+++ b/services/vr/bufferhubd/IBufferHub.cpp
@@ -4,14 +4,69 @@
 namespace android {
 namespace dvr {
 
+class BpBufferHub : public BpInterface<IBufferHub> {
+ public:
+  explicit BpBufferHub(const sp<IBinder>& impl)
+      : BpInterface<IBufferHub>(impl) {}
+
+  sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
+                                 uint32_t layer_count, uint32_t format,
+                                 uint64_t usage,
+                                 uint64_t user_metadata_size) override;
+};
+
 IMPLEMENT_META_INTERFACE(BufferHub, "android.dvr.IBufferHub");
 
+// Transaction code
+enum {
+  CREATE_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+sp<IBufferClient> BpBufferHub::createBuffer(uint32_t width, uint32_t height,
+                                            uint32_t layer_count,
+                                            uint32_t format, uint64_t usage,
+                                            uint64_t user_metadata_size) {
+  Parcel data, reply;
+  status_t ret = NO_ERROR;
+  ret |= data.writeInterfaceToken(IBufferHub::getInterfaceDescriptor());
+  ret |= data.writeUint32(width);
+  ret |= data.writeUint32(height);
+  ret |= data.writeUint32(layer_count);
+  ret |= data.writeUint32(format);
+  ret |= data.writeUint64(usage);
+  ret |= data.writeUint64(user_metadata_size);
+
+  if (ret != NO_ERROR) {
+    ALOGE("BpBufferHub::createBuffer: failed to write into parcel");
+    return nullptr;
+  }
+
+  ret = remote()->transact(CREATE_BUFFER, data, &reply);
+  if (ret == NO_ERROR) {
+    return interface_cast<IBufferClient>(reply.readStrongBinder());
+  } else {
+    ALOGE("BpBufferHub::createBuffer: failed to transact; errno=%d", ret);
+    return nullptr;
+  }
+}
+
 status_t BnBufferHub::onTransact(uint32_t code, const Parcel& data,
                                  Parcel* reply, uint32_t flags) {
   switch (code) {
+    case CREATE_BUFFER: {
+      CHECK_INTERFACE(IBufferHub, data, reply);
+      uint32_t width = data.readUint32();
+      uint32_t height = data.readUint32();
+      uint32_t layer_count = data.readUint32();
+      uint32_t format = data.readUint32();
+      uint64_t usage = data.readUint64();
+      uint64_t user_metadata_size = data.readUint64();
+      sp<IBufferClient> ret = createBuffer(width, height, layer_count, format,
+                                           usage, user_metadata_size);
+      return reply->writeStrongBinder(IInterface::asBinder(ret));
+    } break;
     default:
-      // Should not reach
-      ALOGE("onTransact(): unknown code %u received!", code);
+      // Should not reach except binder defined transactions such as dumpsys
       return BBinder::onTransact(code, data, reply, flags);
   }
 }
diff --git a/services/vr/bufferhubd/buffer_hub_binder.cpp b/services/vr/bufferhubd/buffer_hub_binder.cpp
index b507717..7da1532 100644
--- a/services/vr/bufferhubd/buffer_hub_binder.cpp
+++ b/services/vr/bufferhubd/buffer_hub_binder.cpp
@@ -5,6 +5,7 @@
 #include <binder/ProcessState.h>
 #include <log/log.h>
 #include <private/dvr/buffer_hub_binder.h>
+#include <private/dvr/buffer_node.h>
 
 namespace android {
 namespace dvr {
@@ -13,7 +14,7 @@
     const std::shared_ptr<BufferHubService>& pdx_service) {
   IPCThreadState::self()->disableBackgroundScheduling(true);
 
-  BufferHubBinderService* service = new BufferHubBinderService();
+  sp<BufferHubBinderService> service = new BufferHubBinderService();
   service->pdx_service_ = pdx_service;
 
   // Not using BinderService::publish because need to get an instance of this
@@ -77,5 +78,18 @@
   return ret;
 }
 
+sp<IBufferClient> BufferHubBinderService::createBuffer(
+    uint32_t width, uint32_t height, uint32_t layer_count, uint32_t format,
+    uint64_t usage, uint64_t user_metadata_size) {
+  std::shared_ptr<BufferNode> node = std::make_shared<BufferNode>(
+      width, height, layer_count, format, usage, user_metadata_size);
+
+  sp<BufferClient> client = new BufferClient(node);
+  // Add it to list for bookkeeping and dumpsys.
+  client_list_.push_back(client);
+
+  return client;
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
index 266ae88..0442881 100644
--- a/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
+++ b/services/vr/bufferhubd/include/private/dvr/IBufferHub.h
@@ -3,6 +3,7 @@
 
 #include <binder/IInterface.h>
 #include <binder/Parcel.h>
+#include <private/dvr/IBufferClient.h>
 
 namespace android {
 namespace dvr {
@@ -10,6 +11,11 @@
 class IBufferHub : public IInterface {
  public:
   DECLARE_META_INTERFACE(BufferHub);
+
+  virtual sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
+                                         uint32_t layer_count, uint32_t format,
+                                         uint64_t usage,
+                                         uint64_t user_metadata_size) = 0;
 };
 
 class BnBufferHub : public BnInterface<IBufferHub> {
@@ -18,13 +24,7 @@
                               uint32_t flags = 0);
 };
 
-class BpBufferHub : public BpInterface<IBufferHub> {
- public:
-  explicit BpBufferHub(const sp<IBinder>& impl)
-      : BpInterface<IBufferHub>(impl) {}
-};
-
 }  // namespace dvr
 }  // namespace android
 
-#endif
\ No newline at end of file
+#endif  // ANDROID_DVR_IBUFFERHUB_H
\ No newline at end of file
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_client.h b/services/vr/bufferhubd/include/private/dvr/buffer_client.h
new file mode 100644
index 0000000..20d51ee
--- /dev/null
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_client.h
@@ -0,0 +1,29 @@
+#ifndef ANDROID_DVR_BUFFERCLIENT_H
+#define ANDROID_DVR_BUFFERCLIENT_H
+
+#include <private/dvr/IBufferClient.h>
+#include <private/dvr/buffer_node.h>
+
+namespace android {
+namespace dvr {
+
+class BufferClient : public BnBufferClient {
+ public:
+  // Creates a server-side buffer client from an existing BufferNode. Note that
+  // this funciton takes ownership of the shared_ptr.
+  explicit BufferClient(std::shared_ptr<BufferNode> node)
+      : buffer_node_(std::move(node)){};
+
+  // Binder IPC functions
+  bool isValid() override {
+    return buffer_node_ ? buffer_node_->IsValid() : false;
+  };
+
+ private:
+  std::shared_ptr<BufferNode> buffer_node_;
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_IBUFFERCLIENT_H
\ No newline at end of file
diff --git a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
index e266ff8..11272ae 100644
--- a/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
+++ b/services/vr/bufferhubd/include/private/dvr/buffer_hub_binder.h
@@ -1,8 +1,11 @@
 #ifndef ANDROID_DVR_BUFFER_HUB_BINDER_H
 #define ANDROID_DVR_BUFFER_HUB_BINDER_H
 
+#include <vector>
+
 #include <binder/BinderService.h>
 #include <private/dvr/IBufferHub.h>
+#include <private/dvr/buffer_client.h>
 #include <private/dvr/buffer_hub.h>
 
 namespace android {
@@ -20,8 +23,16 @@
   // Helper function to get the BpReference to this service
   static sp<IBufferHub> getServiceProxy();
 
+  // Binder IPC functions
+  sp<IBufferClient> createBuffer(uint32_t width, uint32_t height,
+                                 uint32_t layer_count, uint32_t format,
+                                 uint64_t usage,
+                                 uint64_t user_metadata_size) override;
+
  private:
   std::shared_ptr<BufferHubService> pdx_service_;
+
+  std::vector<sp<BufferClient>> client_list_;
 };
 
 }  // namespace dvr
diff --git a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
index 587e6db..c4703f1 100644
--- a/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
+++ b/services/vr/bufferhubd/tests/buffer_hub_binder_service-test.cpp
@@ -1,6 +1,8 @@
 #include <gmock/gmock.h>
 #include <gtest/gtest.h>
+#include <private/dvr/IBufferClient.h>
 #include <private/dvr/buffer_hub_binder.h>
+#include <ui/PixelFormat.h>
 
 namespace android {
 namespace dvr {
@@ -8,16 +10,30 @@
 namespace {
 
 using testing::Ne;
+using testing::NotNull;
+
+const int kWidth = 640;
+const int kHeight = 480;
+const int kLayerCount = 1;
+const int kFormat = HAL_PIXEL_FORMAT_RGBA_8888;
+const int kUsage = 0;
+const size_t kUserMetadataSize = 0;
 
 class BufferHubBinderServiceTest : public ::testing::Test {
-  // Add setup and teardown if necessary
+ protected:
+  void SetUp() override {
+    service = BufferHubBinderService::getServiceProxy();
+    ASSERT_THAT(service, Ne(nullptr));
+  }
+
+  sp<IBufferHub> service;
 };
 
-TEST_F(BufferHubBinderServiceTest, TestInitialize) {
-  // Create a new service will kill the current one.
-  // So just check if Binder service is running
-  sp<IBufferHub> service = BufferHubBinderService::getServiceProxy();
-  EXPECT_THAT(service, Ne(nullptr));
+TEST_F(BufferHubBinderServiceTest, TestCreateBuffer) {
+  sp<IBufferClient> bufferClient = service->createBuffer(
+      kWidth, kHeight, kLayerCount, kFormat, kUsage, kUserMetadataSize);
+  ASSERT_THAT(bufferClient, NotNull());
+  EXPECT_TRUE(bufferClient->isValid());
 }
 
 }  // namespace