Fix doxygen syntax.
am: 64b4621f4f

Change-Id: I0e5947d7b313d68a0f41f63bebbb11e3cb9441de
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index ffe931d..94dbebc 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -230,8 +230,8 @@
 static bool g_compress = false;
 static bool g_nohup = false;
 static int g_initialSleepSecs = 0;
-static const char* g_categoriesFile = NULL;
-static const char* g_kernelTraceFuncs = NULL;
+static const char* g_categoriesFile = nullptr;
+static const char* g_kernelTraceFuncs = nullptr;
 static const char* g_debugAppCmdLine = "";
 static const char* g_outputFile = nullptr;
 
@@ -407,7 +407,7 @@
     for (int i = 0; i < MAX_SYS_FILES; i++) {
         const char* path = category.sysfiles[i].path;
         bool req = category.sysfiles[i].required == REQ;
-        if (path != NULL) {
+        if (path != nullptr) {
             if (req) {
                 if (!fileIsWritable(path)) {
                     return false;
@@ -432,7 +432,7 @@
     for (int i = 0; i < MAX_SYS_FILES; i++) {
         const char* path = category.sysfiles[i].path;
         bool req = category.sysfiles[i].required == REQ;
-        if (path != NULL) {
+        if (path != nullptr) {
             if (req) {
                 if (!fileExists(path)) {
                     return false;
@@ -548,10 +548,10 @@
     Vector<String16> services = sm->listServices();
     for (size_t i = 0; i < services.size(); i++) {
         sp<IBinder> obj = sm->checkService(services[i]);
-        if (obj != NULL) {
+        if (obj != nullptr) {
             Parcel data;
             if (obj->transact(IBinder::SYSPROPS_TRANSACTION, data,
-                    NULL, 0) != OK) {
+                    nullptr, 0) != OK) {
                 if (false) {
                     // XXX: For some reason this fails on tablets trying to
                     // poke the "phone" service.  It's not clear whether some
@@ -641,9 +641,9 @@
 {
     int i = 0;
     char* start = cmdline;
-    while (start != NULL) {
+    while (start != nullptr) {
         char* end = strchr(start, ',');
-        if (end != NULL) {
+        if (end != nullptr) {
             *end = '\0';
             end++;
         }
@@ -673,7 +673,7 @@
         const TracingCategory &c = k_categories[i];
         for (int j = 0; j < MAX_SYS_FILES; j++) {
             const char* path = c.sysfiles[j].path;
-            if (path != NULL && fileIsWritable(path)) {
+            if (path != nullptr && fileIsWritable(path)) {
                 ok &= setKernelOptionEnable(path, false);
             }
         }
@@ -709,7 +709,7 @@
                 ok = false;
             }
         }
-        func = strtok(NULL, ",");
+        func = strtok(nullptr, ",");
     }
     free(myFuncs);
     return ok;
@@ -720,7 +720,7 @@
 {
     bool ok = true;
 
-    if (funcs == NULL || funcs[0] == '\0') {
+    if (funcs == nullptr || funcs[0] == '\0') {
         // Disable kernel function tracing.
         if (fileIsWritable(k_currentTracerPath)) {
             ok &= writeStr(k_currentTracerPath, "nop");
@@ -742,7 +742,7 @@
         char* func = strtok(myFuncs, ",");
         while (func) {
             ok &= appendStr(k_ftraceFilterPath, func);
-            func = strtok(NULL, ",");
+            func = strtok(nullptr, ",");
         }
         free(myFuncs);
 
@@ -784,7 +784,7 @@
     if (!categories_file) {
         return true;
     }
-    Tokenizer* tokenizer = NULL;
+    Tokenizer* tokenizer = nullptr;
     if (Tokenizer::open(String8(categories_file), &tokenizer) != NO_ERROR) {
         return false;
     }
@@ -886,7 +886,7 @@
             for (int j = 0; j < MAX_SYS_FILES; j++) {
                 const char* path = c.sysfiles[j].path;
                 bool required = c.sysfiles[j].required == REQ;
-                if (path != NULL) {
+                if (path != nullptr) {
                     if (fileIsWritable(path)) {
                         ok &= setKernelOptionEnable(path, true);
                     } else if (required) {
@@ -911,7 +911,7 @@
     setTraceOverwriteEnable(true);
     setTraceBufferSizeKB(1);
     setPrintTgidEnableIfPresent(false);
-    setKernelTraceFuncs(NULL);
+    setKernelTraceFuncs(nullptr);
     setUserInitiatedTraceProperty(false);
 }
 
@@ -1069,10 +1069,10 @@
     sigemptyset(&sa.sa_mask);
     sa.sa_flags = 0;
     sa.sa_handler = handleSignal;
-    sigaction(SIGHUP, &sa, NULL);
-    sigaction(SIGINT, &sa, NULL);
-    sigaction(SIGQUIT, &sa, NULL);
-    sigaction(SIGTERM, &sa, NULL);
+    sigaction(SIGHUP, &sa, nullptr);
+    sigaction(SIGINT, &sa, nullptr);
+    sigaction(SIGQUIT, &sa, nullptr);
+    sigaction(SIGTERM, &sa, nullptr);
 }
 
 static void listSupportedCategories()
@@ -1162,13 +1162,13 @@
         int ret;
         int option_index = 0;
         static struct option long_options[] = {
-            {"async_start",       no_argument, 0,  0 },
-            {"async_stop",        no_argument, 0,  0 },
-            {"async_dump",        no_argument, 0,  0 },
-            {"only_userspace",    no_argument, 0,  0 },
-            {"list_categories",   no_argument, 0,  0 },
-            {"stream",            no_argument, 0,  0 },
-            {           0,                  0, 0,  0 }
+            {"async_start",       no_argument, nullptr,  0 },
+            {"async_stop",        no_argument, nullptr,  0 },
+            {"async_dump",        no_argument, nullptr,  0 },
+            {"only_userspace",    no_argument, nullptr,  0 },
+            {"list_categories",   no_argument, nullptr,  0 },
+            {"stream",            no_argument, nullptr,  0 },
+            {nullptr,                       0, nullptr,  0 }
         };
 
         ret = getopt_long(argc, argv, "a:b:cf:k:ns:t:zo:",
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
index 4238531..0616add 100644
--- a/cmds/cmd/cmd.cpp
+++ b/cmds/cmd/cmd.cpp
@@ -103,12 +103,12 @@
         }
         if (is_selinux_enabled() && seLinuxContext.size() > 0) {
             String8 seLinuxContext8(seLinuxContext);
-            security_context_t tmp = NULL;
+            security_context_t tmp = nullptr;
             getfilecon(fullPath.string(), &tmp);
             Unique_SecurityContext context(tmp);
             if (checkWrite) {
                 int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
-                        "file", "write", NULL);
+                        "file", "write", nullptr);
                 if (accessGranted != 0) {
 #if DEBUG
                     ALOGD("openFile: failed selinux write check!");
@@ -122,7 +122,7 @@
             }
             if (checkRead) {
                 int accessGranted = selinux_check_access(seLinuxContext8.string(), context.get(),
-                        "file", "read", NULL);
+                        "file", "read", nullptr);
                 if (accessGranted != 0) {
 #if DEBUG
                     ALOGD("openFile: failed selinux read check!");
@@ -174,7 +174,7 @@
 #endif
     sp<IServiceManager> sm = defaultServiceManager();
     fflush(stdout);
-    if (sm == NULL) {
+    if (sm == nullptr) {
         ALOGW("Unable to get default service manager!");
         aerr << "cmd: Unable to get default service manager!" << endl;
         return 20;
@@ -192,7 +192,7 @@
 
         for (size_t i=0; i<services.size(); i++) {
             sp<IBinder> service = sm->checkService(services[i]);
-            if (service != NULL) {
+            if (service != nullptr) {
                 aout << "  " << services[i] << endl;
             }
         }
@@ -205,7 +205,7 @@
     }
     String16 cmd = String16(argv[1]);
     sp<IBinder> service = sm->checkService(cmd);
-    if (service == NULL) {
+    if (service == nullptr) {
         ALOGW("Can't find service %s", argv[1]);
         aerr << "cmd: Can't find service: " << argv[1] << endl;
         return 20;
diff --git a/cmds/dumpstate/DumpstateUtil.cpp b/cmds/dumpstate/DumpstateUtil.cpp
index 85eb464..600a500 100644
--- a/cmds/dumpstate/DumpstateUtil.cpp
+++ b/cmds/dumpstate/DumpstateUtil.cpp
@@ -56,11 +56,11 @@
     timespec ts;
     ts.tv_sec = MSEC_TO_SEC(timeout_ms);
     ts.tv_nsec = (timeout_ms % 1000) * 1000000;
-    int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, NULL, &ts));
+    int ret = TEMP_FAILURE_RETRY(sigtimedwait(&child_mask, nullptr, &ts));
     int saved_errno = errno;
 
     // Set the signals back the way they were.
-    if (sigprocmask(SIG_SETMASK, &old_mask, NULL) == -1) {
+    if (sigprocmask(SIG_SETMASK, &old_mask, nullptr) == -1) {
         printf("*** sigprocmask failed: %s\n", strerror(errno));
         if (ret == 0) {
             return false;
@@ -310,7 +310,7 @@
         struct sigaction sigact;
         memset(&sigact, 0, sizeof(sigact));
         sigact.sa_handler = SIG_IGN;
-        sigaction(SIGPIPE, &sigact, NULL);
+        sigaction(SIGPIPE, &sigact, nullptr);
 
         execvp(path, (char**)args.data());
         // execvp's result will be handled after waitpid_with_timeout() below, but
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index e85274a..2c248c6 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -90,7 +90,7 @@
 
 /* read before root is shed */
 static char cmdline_buf[16384] = "(unknown)";
-static const char *dump_traces_path = NULL;
+static const char *dump_traces_path = nullptr;
 
 // TODO: variables and functions below should be part of dumpstate object
 
@@ -295,7 +295,7 @@
     char path[PATH_MAX];
 
     d = opendir(driverpath);
-    if (d == NULL) {
+    if (d == nullptr) {
         return;
     }
 
@@ -587,7 +587,7 @@
 static int dump_stat_from_fd(const char *title __unused, const char *path, int fd) {
     unsigned long long fields[__STAT_NUMBER_FIELD];
     bool z;
-    char *cp, *buffer = NULL;
+    char *cp, *buffer = nullptr;
     size_t i = 0;
     FILE *fp = fdopen(dup(fd), "rb");
     getline(&buffer, &i, fp);
@@ -1370,7 +1370,7 @@
     printf("== Running Application Services (platform)\n");
     printf("========================================================\n");
 
-    RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform"},
+    RunDumpsys("APP SERVICES PLATFORM", {"activity", "service", "all-platform-non-critical"},
             DUMPSYS_COMPONENTS_OPTIONS);
 
     printf("========================================================\n");
@@ -1686,7 +1686,7 @@
             | O_CLOEXEC | O_NOFOLLOW)));
     if (fd == -1) {
         MYLOGE("open(%s): %s\n", filepath.c_str(), strerror(errno));
-        return NULL;
+        return nullptr;
     }
 
     SHA256_CTX ctx;
@@ -1699,7 +1699,7 @@
             break;
         } else if (bytes_read == -1) {
             MYLOGE("read(%s): %s\n", filepath.c_str(), strerror(errno));
-            return NULL;
+            return nullptr;
         }
 
         SHA256_Update(&ctx, buffer.data(), bytes_read);
@@ -1748,7 +1748,7 @@
     int do_add_date = 0;
     int do_zip_file = 0;
     int do_vibrate = 1;
-    char* use_outfile = 0;
+    char* use_outfile = nullptr;
     int use_socket = 0;
     int use_control_socket = 0;
     int do_fb = 0;
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 9beff98..77f09b7 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -525,13 +525,13 @@
     if (PropertiesHelper::IsDryRun()) return;
 
     /* Get size of kernel buffer */
-    int size = klogctl(KLOG_SIZE_BUFFER, NULL, 0);
+    int size = klogctl(KLOG_SIZE_BUFFER, nullptr, 0);
     if (size <= 0) {
         printf("Unexpected klogctl return value: %d\n\n", size);
         return;
     }
     char *buf = (char *) malloc(size + 1);
-    if (buf == NULL) {
+    if (buf == nullptr) {
         printf("memory allocation failed\n\n");
         return;
     }
@@ -598,7 +598,7 @@
     DurationReporter duration_reporter(title);
     DIR *dirp;
     struct dirent *d;
-    char *newpath = NULL;
+    char *newpath = nullptr;
     const char *slash = "/";
     int retval = 0;
 
@@ -611,7 +611,7 @@
         ++slash;
     }
     dirp = opendir(dir);
-    if (dirp == NULL) {
+    if (dirp == nullptr) {
         retval = -errno;
         MYLOGE("%s: %s\n", dir, strerror(errno));
         return retval;
@@ -620,7 +620,7 @@
     if (!dump_from_fd) {
         dump_from_fd = dump_file_from_fd;
     }
-    for (; ((d = readdir(dirp))); free(newpath), newpath = NULL) {
+    for (; ((d = readdir(dirp))); free(newpath), newpath = nullptr) {
         if ((d->d_name[0] == '.')
          && (((d->d_name[1] == '.') && (d->d_name[2] == '\0'))
           || (d->d_name[1] == '\0'))) {
@@ -648,7 +648,7 @@
             printf("*** %s: %s\n", newpath, strerror(errno));
             continue;
         }
-        (*dump_from_fd)(NULL, newpath, fd.get());
+        (*dump_from_fd)(nullptr, newpath, fd.get());
     }
     closedir(dirp);
     if (!title.empty()) {
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 8f60881..3ada153 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -371,8 +371,8 @@
                                    IServiceManager::DUMP_FLAG_PRIORITY_NORMAL);
     ExpectCheckService("Locksmith");
     ExpectCheckService("Valet");
-    ExpectDumpWithArgs("Locksmith", {"-a", "--dump-priority", "NORMAL"}, "dump1");
-    ExpectDumpWithArgs("Valet", {"-a", "--dump-priority", "NORMAL"}, "dump2");
+    ExpectDumpWithArgs("Locksmith", {"--dump-priority", "NORMAL", "-a"}, "dump1");
+    ExpectDumpWithArgs("Valet", {"--dump-priority", "NORMAL", "-a"}, "dump2");
 
     CallMain({"--priority", "NORMAL"});
 
diff --git a/cmds/flatland/GLHelper.cpp b/cmds/flatland/GLHelper.cpp
index d5b3372..62d2fa1 100644
--- a/cmds/flatland/GLHelper.cpp
+++ b/cmds/flatland/GLHelper.cpp
@@ -29,7 +29,7 @@
     mContext(EGL_NO_CONTEXT),
     mDummySurface(EGL_NO_SURFACE),
     mConfig(0),
-    mShaderPrograms(NULL),
+    mShaderPrograms(nullptr),
     mDitherTexture(0) {
 }
 
@@ -101,12 +101,12 @@
 }
 
 void GLHelper::tearDown() {
-    if (mShaderPrograms != NULL) {
+    if (mShaderPrograms != nullptr) {
         delete[] mShaderPrograms;
-        mShaderPrograms = NULL;
+        mShaderPrograms = nullptr;
     }
 
-    if (mSurfaceComposerClient != NULL) {
+    if (mSurfaceComposerClient != nullptr) {
         mSurfaceComposerClient->dispose();
         mSurfaceComposerClient.clear();
     }
@@ -210,7 +210,7 @@
     glc->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
 
     sp<ANativeWindow> anw = new Surface(producer);
-    EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL);
+    EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr);
     if (s == EGL_NO_SURFACE) {
         fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
         return false;
@@ -223,7 +223,7 @@
 
 bool GLHelper::computeWindowScale(uint32_t w, uint32_t h, float* scale) {
     sp<IBinder> dpy = mSurfaceComposerClient->getBuiltInDisplay(0);
-    if (dpy == NULL) {
+    if (dpy == nullptr) {
         fprintf(stderr, "SurfaceComposer::getBuiltInDisplay failed.\n");
         return false;
     }
@@ -247,7 +247,7 @@
     bool result;
     status_t err;
 
-    if (mSurfaceComposerClient == NULL) {
+    if (mSurfaceComposerClient == nullptr) {
         mSurfaceComposerClient = new SurfaceComposerClient;
     }
     err = mSurfaceComposerClient->initCheck();
@@ -258,7 +258,7 @@
 
     sp<SurfaceControl> sc = mSurfaceComposerClient->createSurface(
             String8("Benchmark"), w, h, PIXEL_FORMAT_RGBA_8888, 0);
-    if (sc == NULL || !sc->isValid()) {
+    if (sc == nullptr || !sc->isValid()) {
         fprintf(stderr, "Failed to create SurfaceControl.\n");
         return false;
     }
@@ -275,7 +275,7 @@
             .apply();
 
     sp<ANativeWindow> anw = sc->getSurface();
-    EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), NULL);
+    EGLSurface s = eglCreateWindowSurface(mDisplay, mConfig, anw.get(), nullptr);
     if (s == EGL_NO_SURFACE) {
         fprintf(stderr, "eglCreateWindowSurface error: %#x\n", eglGetError());
         return false;
@@ -294,7 +294,7 @@
         return false;
     }
 
-    glShaderSource(shader, 1, &src, NULL);
+    glShaderSource(shader, 1, &src, nullptr);
     glCompileShader(shader);
 
     GLint compiled = 0;
@@ -305,7 +305,7 @@
         if (infoLen) {
             char* buf = new char[infoLen];
             if (buf) {
-                glGetShaderInfoLog(shader, infoLen, NULL, buf);
+                glGetShaderInfoLog(shader, infoLen, nullptr, buf);
                 fprintf(stderr, "Shader compile log:\n%s\n", buf);
                 delete[] buf;
             }
@@ -318,21 +318,21 @@
 }
 
 static void printShaderSource(const char* const* src) {
-    for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
+    for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
         fprintf(stderr, "%3zu: %s\n", i+1, src[i]);
     }
 }
 
 static const char* makeShaderString(const char* const* src) {
     size_t len = 0;
-    for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
+    for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
         // The +1 is for the '\n' that will be added.
         len += strlen(src[i]) + 1;
     }
 
     char* result = new char[len+1];
     char* end = result;
-    for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != NULL; i++) {
+    for (size_t i = 0; i < MAX_SHADER_LINES && src[i] != nullptr; i++) {
         strcpy(end, src[i]);
         end += strlen(src[i]);
         *end = '\n';
@@ -376,7 +376,7 @@
         if (bufLength) {
             char* buf = new char[bufLength];
             if (buf) {
-                glGetProgramInfoLog(program, bufLength, NULL, buf);
+                glGetProgramInfoLog(program, bufLength, nullptr, buf);
                 fprintf(stderr, "Program link log:\n%s\n", buf);
                 delete[] buf;
             }
diff --git a/cmds/flatland/Main.cpp b/cmds/flatland/Main.cpp
index 3d7cac0..7ceb397 100644
--- a/cmds/flatland/Main.cpp
+++ b/cmds/flatland/Main.cpp
@@ -284,7 +284,7 @@
 public:
 
     Layer() :
-        mGLHelper(NULL),
+        mGLHelper(nullptr),
         mSurface(EGL_NO_SURFACE) {
     }
 
@@ -316,23 +316,23 @@
     }
 
     void tearDown() {
-        if (mComposer != NULL) {
+        if (mComposer != nullptr) {
             mComposer->tearDown();
             delete mComposer;
-            mComposer = NULL;
+            mComposer = nullptr;
         }
 
-        if (mRenderer != NULL) {
+        if (mRenderer != nullptr) {
             mRenderer->tearDown();
             delete mRenderer;
-            mRenderer = NULL;
+            mRenderer = nullptr;
         }
 
         if (mSurface != EGL_NO_SURFACE) {
             mGLHelper->destroySurface(&mSurface);
             mGLConsumer->abandon();
         }
-        mGLHelper = NULL;
+        mGLHelper = nullptr;
         mGLConsumer.clear();
     }
 
@@ -377,7 +377,7 @@
         mDesc(desc),
         mInstance(instance),
         mNumLayers(countLayers(desc)),
-        mGLHelper(NULL),
+        mGLHelper(nullptr),
         mSurface(EGL_NO_SURFACE),
         mWindowSurface(EGL_NO_SURFACE) {
     }
@@ -443,7 +443,7 @@
             mLayers[i].tearDown();
         }
 
-        if (mGLHelper != NULL) {
+        if (mGLHelper != nullptr) {
             if (mWindowSurface != EGL_NO_SURFACE) {
                 mGLHelper->destroySurface(&mWindowSurface);
             }
@@ -453,7 +453,7 @@
             mSurfaceControl.clear();
             mGLHelper->tearDown();
             delete mGLHelper;
-            mGLHelper = NULL;
+            mGLHelper = nullptr;
         }
     }
 
@@ -553,7 +553,7 @@
     static size_t countLayers(const BenchmarkDesc& desc) {
         size_t i;
         for (i = 0; i < MAX_NUM_LAYERS; i++) {
-            if (desc.layers[i].rendererFactory == NULL) {
+            if (desc.layers[i].rendererFactory == nullptr) {
                 break;
             }
         }
diff --git a/cmds/installd/CacheItem.cpp b/cmds/installd/CacheItem.cpp
index 515f915..e29ff4c 100644
--- a/cmds/installd/CacheItem.cpp
+++ b/cmds/installd/CacheItem.cpp
@@ -73,7 +73,7 @@
         FTS *fts;
         FTSENT *p;
         char *argv[] = { (char*) path.c_str(), nullptr };
-        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
             PLOG(WARNING) << "Failed to fts_open " << path;
             return -1;
         }
diff --git a/cmds/installd/CacheTracker.cpp b/cmds/installd/CacheTracker.cpp
index ea0cd9e..a7242c3 100644
--- a/cmds/installd/CacheTracker.cpp
+++ b/cmds/installd/CacheTracker.cpp
@@ -103,7 +103,7 @@
     FTS *fts;
     FTSENT *p;
     char *argv[] = { (char*) path.c_str(), nullptr };
-    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
         PLOG(WARNING) << "Failed to fts_open " << path;
         return;
     }
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 860a68b..9e32bc6 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -715,7 +715,7 @@
         auto ce_path = create_data_user_ce_path(uuid_, user);
         auto de_path = create_data_user_de_path(uuid_, user);
         char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(), nullptr };
-        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
             return error("Failed to fts_open");
         }
         while ((p = fts_read(fts)) != nullptr) {
@@ -840,7 +840,7 @@
         };
 
         LOG(DEBUG) << "Copying " << from << " to " << to;
-        int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+        int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
         if (rc != 0) {
             res = error(rc, "Failed copying " + from + " to " + to);
             goto fail;
@@ -886,7 +886,7 @@
             argv[7] = (char*) to.c_str();
 
             LOG(DEBUG) << "Copying " << from << " to " << to;
-            int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+            int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
             if (rc != 0) {
                 res = error(rc, "Failed copying " + from + " to " + to);
                 goto fail;
@@ -899,7 +899,7 @@
             argv[7] = (char*) to.c_str();
 
             LOG(DEBUG) << "Copying " << from << " to " << to;
-            int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, NULL, false, true);
+            int rc = android_fork_execvp(ARRAY_SIZE(argv), argv, nullptr, false, true);
             if (rc != 0) {
                 res = error(rc, "Failed copying " + from + " to " + to);
                 goto fail;
@@ -922,20 +922,20 @@
     // Nuke everything we might have already copied
     {
         auto to = create_data_app_package_path(to_uuid, data_app_name);
-        if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+        if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
             LOG(WARNING) << "Failed to rollback " << to;
         }
     }
     for (auto user : users) {
         {
             auto to = create_data_user_de_package_path(to_uuid, user, package_name);
-            if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+            if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
                 LOG(WARNING) << "Failed to rollback " << to;
             }
         }
         {
             auto to = create_data_user_ce_package_path(to_uuid, user, package_name);
-            if (delete_dir_contents(to.c_str(), 1, NULL) != 0) {
+            if (delete_dir_contents(to.c_str(), 1, nullptr) != 0) {
                 LOG(WARNING) << "Failed to rollback " << to;
             }
         }
@@ -1045,10 +1045,10 @@
             auto media_path = findDataMediaPath(uuid, user) + "/Android/data/";
             char *argv[] = { (char*) ce_path.c_str(), (char*) de_path.c_str(),
                     (char*) media_path.c_str(), nullptr };
-            if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+            if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
                 return error("Failed to fts_open");
             }
-            while ((p = fts_read(fts)) != NULL) {
+            while ((p = fts_read(fts)) != nullptr) {
                 if (p->fts_info == FTS_D && p->fts_level == 1) {
                     uid_t uid = p->fts_statp->st_uid;
                     if (multiuser_get_app_id(uid) == AID_MEDIA_RW) {
@@ -1398,11 +1398,11 @@
     FTS *fts;
     FTSENT *p;
     char *argv[] = { (char*) path.c_str(), nullptr };
-    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
         PLOG(ERROR) << "Failed to fts_open " << path;
         return;
     }
-    while ((p = fts_read(fts)) != NULL) {
+    while ((p = fts_read(fts)) != nullptr) {
         p->fts_number = p->fts_parent->fts_number;
         switch (p->fts_info) {
         case FTS_D:
@@ -1808,10 +1808,10 @@
         FTSENT *p;
         auto path = create_data_media_path(uuid_, userId);
         char *argv[] = { (char*) path.c_str(), nullptr };
-        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+        if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
             return error("Failed to fts_open " + path);
         }
-        while ((p = fts_read(fts)) != NULL) {
+        while ((p = fts_read(fts)) != nullptr) {
             char* ext;
             int64_t size = (p->fts_statp->st_blocks * 512);
             switch (p->fts_info) {
@@ -2040,7 +2040,7 @@
         }
     } else {
         if (S_ISDIR(libStat.st_mode)) {
-            if (delete_dir_contents(libsymlink, 1, NULL) < 0) {
+            if (delete_dir_contents(libsymlink, 1, nullptr) < 0) {
                 res = error("Failed to delete " + _libsymlink);
                 goto out;
             }
@@ -2082,14 +2082,14 @@
 static void run_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
 {
     execl(kIdMapPath, kIdMapPath, "--fd", target_apk, overlay_apk,
-            StringPrintf("%d", idmap_fd).c_str(), (char*)NULL);
+            StringPrintf("%d", idmap_fd).c_str(), (char*)nullptr);
     PLOG(ERROR) << "execl (" << kIdMapPath << ") failed";
 }
 
 static void run_verify_idmap(const char *target_apk, const char *overlay_apk, int idmap_fd)
 {
     execl(kIdMapPath, kIdMapPath, "--verify", target_apk, overlay_apk,
-            StringPrintf("%d", idmap_fd).c_str(), (char*)NULL);
+            StringPrintf("%d", idmap_fd).c_str(), (char*)nullptr);
     PLOG(ERROR) << "execl (" << kIdMapPath << ") failed";
 }
 
@@ -2140,7 +2140,7 @@
 static int flatten_path(const char *prefix, const char *suffix,
         const char *overlay_path, char *idmap_path, size_t N)
 {
-    if (overlay_path == NULL || idmap_path == NULL) {
+    if (overlay_path == nullptr || idmap_path == nullptr) {
         return -1;
     }
     const size_t len_overlay_path = strlen(overlay_path);
@@ -2481,7 +2481,7 @@
                      std::to_string(shmSize));
     }
     auto data = std::unique_ptr<void, std::function<void (void *)>>(
-        mmap(NULL, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0),
+        mmap(nullptr, contentSize, PROT_READ, MAP_SHARED, verityInputAshmem.get(), 0),
         [contentSize] (void* ptr) {
           if (ptr != MAP_FAILED) {
             munmap(ptr, contentSize);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 0fd2dd4..0e78e3a 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -190,9 +190,9 @@
   strlcpy(buf, str, sizeof(buf));
   char *pBuf = buf;
 
-  while(strtok_r(pBuf, " ", &ctx) != NULL) {
+  while(strtok_r(pBuf, " ", &ctx) != nullptr) {
     count++;
-    pBuf = NULL;
+    pBuf = nullptr;
   }
 
   return count;
@@ -205,9 +205,9 @@
   char *tok;
   char *pBuf = buf;
 
-  while((tok = strtok_r(pBuf, " ", &ctx)) != NULL) {
+  while((tok = strtok_r(pBuf, " ", &ctx)) != nullptr) {
     argv[count++] = tok;
-    pBuf = NULL;
+    pBuf = nullptr;
   }
 
   return count;
@@ -216,7 +216,7 @@
 static const char* get_location_from_path(const char* path) {
     static constexpr char kLocationSeparator = '/';
     const char *location = strrchr(path, kLocationSeparator);
-    if (location == NULL) {
+    if (location == nullptr) {
         return path;
     } else {
         // Skip the separator character.
@@ -243,17 +243,17 @@
     const char* relative_input_file_name = get_location_from_path(input_file_name);
 
     char dex2oat_Xms_flag[kPropertyValueMax];
-    bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, NULL) > 0;
+    bool have_dex2oat_Xms_flag = get_property("dalvik.vm.dex2oat-Xms", dex2oat_Xms_flag, nullptr) > 0;
 
     char dex2oat_Xmx_flag[kPropertyValueMax];
-    bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, NULL) > 0;
+    bool have_dex2oat_Xmx_flag = get_property("dalvik.vm.dex2oat-Xmx", dex2oat_Xmx_flag, nullptr) > 0;
 
     char dex2oat_threads_buf[kPropertyValueMax];
     bool have_dex2oat_threads_flag = get_property(post_bootcomplete
                                                       ? "dalvik.vm.dex2oat-threads"
                                                       : "dalvik.vm.boot-dex2oat-threads",
                                                   dex2oat_threads_buf,
-                                                  NULL) > 0;
+                                                  nullptr) > 0;
     char dex2oat_threads_arg[kPropertyValueMax + 2];
     if (have_dex2oat_threads_flag) {
         sprintf(dex2oat_threads_arg, "-j%s", dex2oat_threads_buf);
@@ -263,20 +263,20 @@
     sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);
     char dex2oat_isa_features[kPropertyValueMax];
     bool have_dex2oat_isa_features = get_property(dex2oat_isa_features_key,
-                                                  dex2oat_isa_features, NULL) > 0;
+                                                  dex2oat_isa_features, nullptr) > 0;
 
     char dex2oat_isa_variant_key[kPropertyKeyMax];
     sprintf(dex2oat_isa_variant_key, "dalvik.vm.isa.%s.variant", instruction_set);
     char dex2oat_isa_variant[kPropertyValueMax];
     bool have_dex2oat_isa_variant = get_property(dex2oat_isa_variant_key,
-                                                 dex2oat_isa_variant, NULL) > 0;
+                                                 dex2oat_isa_variant, nullptr) > 0;
 
     const char *dex2oat_norelocation = "-Xnorelocate";
     bool have_dex2oat_relocation_skip_flag = false;
 
     char dex2oat_flags[kPropertyValueMax];
     int dex2oat_flags_count = get_property("dalvik.vm.dex2oat-flags",
-                                 dex2oat_flags, NULL) <= 0 ? 0 : split_count(dex2oat_flags);
+                                 dex2oat_flags, nullptr) <= 0 ? 0 : split_count(dex2oat_flags);
     ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags);
 
     // If we are booting without the real /data, don't spend time compiling.
@@ -291,14 +291,14 @@
     char app_image_format[kPropertyValueMax];
     char image_format_arg[strlen("--image-format=") + kPropertyValueMax];
     bool have_app_image_format =
-            image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
+            image_fd >= 0 && get_property("dalvik.vm.appimageformat", app_image_format, nullptr) > 0;
     if (have_app_image_format) {
         sprintf(image_format_arg, "--image-format=%s", app_image_format);
     }
 
     char dex2oat_large_app_threshold[kPropertyValueMax];
     bool have_dex2oat_large_app_threshold =
-            get_property("dalvik.vm.dex2oat-very-large", dex2oat_large_app_threshold, NULL) > 0;
+            get_property("dalvik.vm.dex2oat-very-large", dex2oat_large_app_threshold, nullptr) > 0;
     char dex2oat_large_app_threshold_arg[strlen("--very-large-app-threshold=") + kPropertyValueMax];
     if (have_dex2oat_large_app_threshold) {
         sprintf(dex2oat_large_app_threshold_arg,
@@ -400,7 +400,7 @@
     if (!have_dex2oat_compiler_filter_flag) {
         char dex2oat_compiler_filter_flag[kPropertyValueMax];
         have_dex2oat_compiler_filter_flag = get_property("dalvik.vm.dex2oat-filter",
-                                                         dex2oat_compiler_filter_flag, NULL) > 0;
+                                                         dex2oat_compiler_filter_flag, nullptr) > 0;
         if (have_dex2oat_compiler_filter_flag) {
             sprintf(dex2oat_compiler_filter_arg,
                     "--compiler-filter=%s",
@@ -552,7 +552,7 @@
         argv[i++] = compilation_reason_arg.c_str();
     }
     // Do not add after dex2oat_flags, they should override others for debugging.
-    argv[i] = NULL;
+    argv[i] = nullptr;
 
     execv(dex2oat_bin, (char * const *)argv);
     PLOG(ERROR) << "execv(" << dex2oat_bin << ") failed";
@@ -792,7 +792,7 @@
     }
 
     // Do not add after dex2oat_flags, they should override others for debugging.
-    argv[i] = NULL;
+    argv[i] = nullptr;
 
     execv(profman_bin, (char * const *)argv);
     PLOG(ERROR) << "execv(" << profman_bin << ") failed";
@@ -948,7 +948,7 @@
     for (const std::string& profman_arg : profman_args) {
         argv[i++] = profman_arg.c_str();
     }
-    argv[i] = NULL;
+    argv[i] = nullptr;
 
     execv(PROFMAN_BIN, (char * const *)argv);
     PLOG(ERROR) << "execv(" << PROFMAN_BIN << ") failed";
@@ -1308,7 +1308,7 @@
     }
     char app_image_format[kPropertyValueMax];
     bool have_app_image_format =
-            get_property("dalvik.vm.appimageformat", app_image_format, NULL) > 0;
+            get_property("dalvik.vm.appimageformat", app_image_format, nullptr) > 0;
     if (!have_app_image_format) {
         return Dex2oatFileWrapper();
     }
@@ -1629,7 +1629,7 @@
     if (class_loader_context != nullptr) {
         argv[i++] = class_loader_context_arg.c_str();
     }
-    argv[i] = NULL;
+    argv[i] = nullptr;
 
     execv(dexoptanalyzer_bin, (char * const *)argv);
     ALOGE("execv(%s) failed: %s\n", dexoptanalyzer_bin, strerror(errno));
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 95ed2ff..673ff0d 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -107,7 +107,7 @@
         DIR *dir;
         struct dirent *dirent;
         dir = opendir("/data/user");
-        if (dir != NULL) {
+        if (dir != nullptr) {
             while ((dirent = readdir(dir))) {
                 const char *name = dirent->d_name;
 
@@ -146,10 +146,10 @@
             closedir(dir);
 
             if (access(keychain_added_dir, F_OK) == 0) {
-                delete_dir_contents(keychain_added_dir, 1, 0);
+                delete_dir_contents(keychain_added_dir, 1, nullptr);
             }
             if (access(keychain_removed_dir, F_OK) == 0) {
-                delete_dir_contents(keychain_removed_dir, 1, 0);
+                delete_dir_contents(keychain_removed_dir, 1, nullptr);
             }
         }
 
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 1ff45e4..48f9eb4 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -310,7 +310,7 @@
 
     std::string path(create_data_path(volume_uuid) + "/" + SECONDARY_USER_PREFIX);
     DIR* dir = opendir(path.c_str());
-    if (dir == NULL) {
+    if (dir == nullptr) {
         // Unable to discover other users, but at least return owner
         PLOG(ERROR) << "Failed to opendir " << path;
         return users;
@@ -340,13 +340,13 @@
     FTSENT *p;
     int64_t matchedSize = 0;
     char *argv[] = { (char*) path.c_str(), nullptr };
-    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
         if (errno != ENOENT) {
             PLOG(ERROR) << "Failed to fts_open " << path;
         }
         return -1;
     }
-    while ((p = fts_read(fts)) != NULL) {
+    while ((p = fts_read(fts)) != nullptr) {
         switch (p->fts_info) {
         case FTS_D:
         case FTS_DEFAULT:
@@ -469,7 +469,7 @@
                 continue;
             }
             subdir = fdopendir(subfd);
-            if (subdir == NULL) {
+            if (subdir == nullptr) {
                 ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
                 close(subfd);
                 result = -1;
@@ -495,11 +495,11 @@
 }
 
 int delete_dir_contents(const std::string& pathname, bool ignore_if_missing) {
-    return delete_dir_contents(pathname.c_str(), 0, NULL, ignore_if_missing);
+    return delete_dir_contents(pathname.c_str(), 0, nullptr, ignore_if_missing);
 }
 
 int delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing) {
-    return delete_dir_contents(pathname.c_str(), 1, NULL, ignore_if_missing);
+    return delete_dir_contents(pathname.c_str(), 1, nullptr, ignore_if_missing);
 }
 
 int delete_dir_contents(const char *pathname,
@@ -511,7 +511,7 @@
     DIR *d;
 
     d = opendir(pathname);
-    if (d == NULL) {
+    if (d == nullptr) {
         if (ignore_if_missing && (errno == ENOENT)) {
             return 0;
         }
@@ -540,12 +540,12 @@
         return -1;
     }
     d = fdopendir(fd);
-    if (d == NULL) {
+    if (d == nullptr) {
         ALOGE("Couldn't fdopendir %s: %s\n", name, strerror(errno));
         close(fd);
         return -1;
     }
-    res = _delete_dir_contents(d, 0);
+    res = _delete_dir_contents(d, nullptr);
     closedir(d);
     return res;
 }
@@ -573,7 +573,7 @@
     }
 
     DIR *ds = fdopendir(sdfd);
-    if (ds == NULL) {
+    if (ds == nullptr) {
         ALOGE("Couldn't fdopendir: %s\n", strerror(errno));
         return -1;
     }
@@ -619,18 +619,18 @@
                    uid_t group)
 {
     int res = 0;
-    DIR *ds = NULL;
-    DIR *dd = NULL;
+    DIR *ds = nullptr;
+    DIR *dd = nullptr;
 
     ds = opendir(srcname);
-    if (ds == NULL) {
+    if (ds == nullptr) {
         ALOGE("Couldn't opendir %s: %s\n", srcname, strerror(errno));
         return -errno;
     }
 
     mkdir(dstname, 0600);
     dd = opendir(dstname);
-    if (dd == NULL) {
+    if (dd == nullptr) {
         ALOGE("Couldn't opendir %s: %s\n", dstname, strerror(errno));
         closedir(ds);
         return -errno;
@@ -964,11 +964,11 @@
     FTS *fts;
     FTSENT *p;
     char *argv[] = { (char*) path.c_str(), nullptr };
-    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, NULL))) {
+    if (!(fts = fts_open(argv, FTS_PHYSICAL | FTS_NOCHDIR | FTS_XDEV, nullptr))) {
         PLOG(ERROR) << "Failed to fts_open " << path;
         return -1;
     }
-    while ((p = fts_read(fts)) != NULL) {
+    while ((p = fts_read(fts)) != nullptr) {
         switch (p->fts_info) {
         case FTS_DP:
             if (chmod(p->fts_path, target_mode) != 0) {
@@ -1037,7 +1037,7 @@
             }
 
             DIR* subdir = fdopendir(subdir_fd);
-            if (subdir == NULL) {
+            if (subdir == nullptr) {
                 PLOG(WARNING) << "Could not open dir path " << local_path;
                 result = false;
                 continue;
@@ -1055,7 +1055,7 @@
 
 bool collect_profiles(std::vector<std::string>* profiles_paths) {
     DIR* d = opendir(android_profiles_dir.c_str());
-    if (d == NULL) {
+    if (d == nullptr) {
         return false;
     } else {
         return collect_profiles(d, android_profiles_dir, profiles_paths);
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 09eeaa8..8d5f0d2 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -1073,9 +1073,9 @@
         i++;
     }
     // getopt_long last option has all zeros
-    ret[i].name = NULL;
+    ret[i].name = nullptr;
     ret[i].has_arg = 0;
-    ret[i].flag = NULL;
+    ret[i].flag = nullptr;
     ret[i].val = 0;
 
     return ret;
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
index 3828bbf..87d75ac 100644
--- a/cmds/lshal/PipeRelay.cpp
+++ b/cmds/lshal/PipeRelay.cpp
@@ -78,7 +78,7 @@
 PipeRelay::~PipeRelay() {
     CloseFd(&mFds[1]);
 
-    if (mThread != NULL) {
+    if (mThread != nullptr) {
         mThread->join();
         mThread.clear();
     }
diff --git a/cmds/lshal/Timeout.h b/cmds/lshal/Timeout.h
index c940404..58119a6 100644
--- a/cmds/lshal/Timeout.h
+++ b/cmds/lshal/Timeout.h
@@ -57,7 +57,7 @@
     BackgroundTaskState &state = *static_cast<BackgroundTaskState *>(data);
     state();
     state.notify();
-    return NULL;
+    return nullptr;
 }
 
 template<class R, class P>
@@ -65,7 +65,7 @@
     auto now = std::chrono::system_clock::now();
     BackgroundTaskState state{std::forward<decltype(func)>(func)};
     pthread_t thread;
-    if (pthread_create(&thread, NULL, callAndNotify, &state)) {
+    if (pthread_create(&thread, nullptr, callAndNotify, &state)) {
         std::cerr << "FATAL: could not create background thread." << std::endl;
         return false;
     }
@@ -73,7 +73,7 @@
     if (!success) {
         pthread_kill(thread, SIGINT);
     }
-    pthread_join(thread, NULL);
+    pthread_join(thread, nullptr);
     return success;
 }
 
diff --git a/cmds/rawbu/backup.cpp b/cmds/rawbu/backup.cpp
index 0072281..8b20e3e 100644
--- a/cmds/rawbu/backup.cpp
+++ b/cmds/rawbu/backup.cpp
@@ -38,7 +38,7 @@
 static struct stat statBuffer;
 
 static char copyBuffer[8192];
-static char *backupFilePath = NULL;
+static char *backupFilePath = nullptr;
 
 static uint32_t inputFileVersion;
 
@@ -58,7 +58,7 @@
     { "/data/system/batterystats.bin", SPECIAL_NO_TOUCH },
     { "/data/system/location", SPECIAL_NO_TOUCH },
     { "/data/dalvik-cache", SPECIAL_NO_BACKUP },
-    { NULL, 0 },
+    { nullptr, 0 },
 };
 
 /* This is just copied from the shell's built-in wipe command. */
@@ -71,7 +71,7 @@
 
     dir = opendir(path);
 
-    if (dir == NULL) {
+    if (dir == nullptr) {
         fprintf (stderr, "Error opendir'ing %s: %s\n",
                     path, strerror(errno));
         return 0;
@@ -87,7 +87,7 @@
     for (;;) {
         de = readdir(dir);
 
-        if (de == NULL) {
+        if (de == nullptr) {
             break;
         }
 
@@ -115,7 +115,7 @@
             }
         }
         
-        if (!noBackup && SKIP_PATHS[i].path != NULL) {
+        if (!noBackup && SKIP_PATHS[i].path != nullptr) {
             // This is a SPECIAL_NO_TOUCH directory.
             continue;
         }
@@ -203,7 +203,7 @@
         int amt = size > (off_t)sizeof(copyBuffer) ? sizeof(copyBuffer) : (int)size;
         int readLen = fread(copyBuffer, 1, amt, src);
         if (readLen <= 0) {
-            if (srcName != NULL) {
+            if (srcName != nullptr) {
                 fprintf(stderr, "unable to read source (%d of %ld bytes) file '%s': %s\n",
                     amt, origSize, srcName, errno != 0 ? strerror(errno) : "unexpected EOF");
             } else {
@@ -214,7 +214,7 @@
         }
         int writeLen = fwrite(copyBuffer, 1, readLen, dest); 
         if (writeLen != readLen) {
-            if (destName != NULL) {
+            if (destName != nullptr) {
                 fprintf(stderr, "unable to write file (%d of %d bytes) '%s': '%s'\n",
                     writeLen, readLen, destName, strerror(errno));
             } else {
@@ -256,14 +256,14 @@
 {
     DIR *dir;
     struct dirent *de;
-    char* fullPath = NULL;
+    char* fullPath = nullptr;
     int srcLen = strlen(srcPath);
     int result = 1;
     int i;
     
     dir = opendir(srcPath);
 
-    if (dir == NULL) {
+    if (dir == nullptr) {
         fprintf (stderr, "error opendir'ing '%s': %s\n",
                     srcPath, strerror(errno));
         return 0;
@@ -272,7 +272,7 @@
     for (;;) {
         de = readdir(dir);
 
-        if (de == NULL) {
+        if (de == nullptr) {
             break;
         }
 
@@ -283,7 +283,7 @@
             continue;
         }
 
-        if (fullPath != NULL) {
+        if (fullPath != nullptr) {
             free(fullPath);
         }
         fullPath = (char*)malloc(srcLen + strlen(de->d_name) + 2);
@@ -298,7 +298,7 @@
                     break;
                 }
             }
-            if (SKIP_PATHS[i].path != NULL) {
+            if (SKIP_PATHS[i].path != nullptr) {
                 continue;
             }
         }
@@ -343,14 +343,14 @@
             }
             
             FILE* src = fopen(fullPath, "r");
-            if (src == NULL) {
+            if (src == nullptr) {
                 fprintf(stderr, "unable to open source file '%s': %s\n",
                     fullPath, strerror(errno));
                 result = 0;
                 goto done;
             }
             
-            int copyres = copy_file(fh, src, size, NULL, fullPath);
+            int copyres = copy_file(fh, src, size, nullptr, fullPath);
             fclose(src);
             if (!copyres) {
                 result = 0;
@@ -360,7 +360,7 @@
     }
 
 done:
-    if (fullPath != NULL) {
+    if (fullPath != nullptr) {
         free(fullPath);
     }
     
@@ -374,7 +374,7 @@
     int res = -1;
     
     FILE* fh = fopen(destPath, "w");
-    if (fh == NULL) {
+    if (fh == nullptr) {
         fprintf(stderr, "unable to open destination '%s': %s\n",
                 destPath, strerror(errno));
         return -1;
@@ -504,7 +504,7 @@
     int res = -1;
     
     FILE* fh = fopen(srcPath, "r");
-    if (fh == NULL) {
+    if (fh == nullptr) {
         fprintf(stderr, "Unable to open source '%s': %s\n",
                 srcPath, strerror(errno));
         return -1;
@@ -534,7 +534,7 @@
 
     while (1) {
         int type;
-        char* path = NULL;
+        char* path = nullptr;
         if (read_header(fh, &type, &path, &statBuffer) == 0) {
             goto done;
         }
@@ -570,14 +570,14 @@
             printf("Restoring file %s...\n", path);
             
             FILE* dest = fopen(path, "w");
-            if (dest == NULL) {
+            if (dest == nullptr) {
                 fprintf(stderr, "unable to open destination file '%s': %s\n",
                     path, strerror(errno));
                 free(path);
                 goto done;
             }
             
-            int copyres = copy_file(dest, fh, size, path, NULL);
+            int copyres = copy_file(dest, fh, size, path, nullptr);
             fclose(dest);
             if (!copyres) {
                 free(path);
diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp
index bc11256..34a3fdc 100644
--- a/cmds/service/service.cpp
+++ b/cmds/service/service.cpp
@@ -30,7 +30,7 @@
 
 void writeString16(Parcel& parcel, const char* string)
 {
-    if (string != NULL)
+    if (string != nullptr)
     {
         parcel.writeString16(String16(string));
     }
@@ -43,7 +43,7 @@
 // get the name of the generic interface we hold a reference to
 static String16 get_interface_name(sp<IBinder> service)
 {
-    if (service != NULL) {
+    if (service != nullptr) {
         Parcel data, reply;
         status_t err = service->transact(IBinder::INTERFACE_TRANSACTION, data, &reply);
         if (err == NO_ERROR) {
@@ -93,7 +93,7 @@
 #endif
     sp<IServiceManager> sm = defaultServiceManager();
     fflush(stdout);
-    if (sm == NULL) {
+    if (sm == nullptr) {
         aerr << "service: Unable to get default service manager!" << endl;
         return 20;
     }
@@ -106,7 +106,7 @@
             if (optind < argc) {
                 sp<IBinder> service = sm->checkService(String16(argv[optind]));
                 aout << "Service " << argv[optind] <<
-                    (service == NULL ? ": not found" : ": found") << endl;
+                    (service == nullptr ? ": not found" : ": found") << endl;
             } else {
                 aerr << "service: No service specified for check" << endl;
                 wantsUsage = true;
@@ -131,7 +131,7 @@
                 sp<IBinder> service = sm->checkService(String16(argv[optind++]));
                 String16 ifName = get_interface_name(service);
                 int32_t code = atoi(argv[optind++]);
-                if (service != NULL && ifName.size() > 0) {
+                if (service != nullptr && ifName.size() > 0) {
                     Parcel data, reply;
 
                     // the interface name is first
@@ -186,28 +186,28 @@
                             data.writeDouble(atof(argv[optind++]));
                         } else if (strcmp(argv[optind], "null") == 0) {
                             optind++;
-                            data.writeStrongBinder(NULL);
+                            data.writeStrongBinder(nullptr);
                         } else if (strcmp(argv[optind], "intent") == 0) {
                         	
-                        	char* action = NULL;
-                        	char* dataArg = NULL;
-                        	char* type = NULL;
+                        	char* action = nullptr;
+                        	char* dataArg = nullptr;
+                        	char* type = nullptr;
                         	int launchFlags = 0;
-                        	char* component = NULL;
+                        	char* component = nullptr;
                         	int categoryCount = 0;
                         	char* categories[16];
                         	
-                        	char* context1 = NULL;
+                        	char* context1 = nullptr;
                         	
                             optind++;
                             
                         	while (optind < argc)
                         	{
                         		char* key = strtok_r(argv[optind], "=", &context1);
-                        		char* value = strtok_r(NULL, "=", &context1);
+                        		char* value = strtok_r(nullptr, "=", &context1);
                                 
                                 // we have reached the end of the XXX=XXX args.
-                                if (key == NULL) break;
+                                if (key == nullptr) break;
                         		
                         		if (strcmp(key, "action") == 0)
                         		{
@@ -231,14 +231,14 @@
                         		}
                         		else if (strcmp(key, "categories") == 0)
                         		{
-                        			char* context2 = NULL;
+                        			char* context2 = nullptr;
                         			int categoryCount = 0;
                         			categories[categoryCount] = strtok_r(value, ",", &context2);
                         			
-                        			while (categories[categoryCount] != NULL)
+                        			while (categories[categoryCount] != nullptr)
                         			{
                         				categoryCount++;
-                        				categories[categoryCount] = strtok_r(NULL, ",", &context2);
+                        				categories[categoryCount] = strtok_r(nullptr, ",", &context2);
                         			}
                         		}
                                 
diff --git a/cmds/surfacereplayer/replayer/Main.cpp b/cmds/surfacereplayer/replayer/Main.cpp
index 7090bdb..fbfcacf 100644
--- a/cmds/surfacereplayer/replayer/Main.cpp
+++ b/cmds/surfacereplayer/replayer/Main.cpp
@@ -94,7 +94,7 @@
     }
 
     char** input = argv + optind;
-    if (input[0] == NULL) {
+    if (input[0] == nullptr) {
         std::cerr << "No trace file provided...exiting" << std::endl;
         abort();
     }
diff --git a/data/etc/android.hardware.face.xml b/data/etc/android.hardware.face.xml
new file mode 100644
index 0000000..abd23fb
--- /dev/null
+++ b/data/etc/android.hardware.face.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 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.
+-->
+
+<!-- This is the standard set of features for a biometric face authentication sensor. -->
+<permissions>
+    <feature name="android.hardware.face" />
+</permissions>
diff --git a/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h b/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
index b32c92e..67abc68 100644
--- a/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
+++ b/headers/media_plugin/media/arcvideobridge/IArcVideoBridge.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_IARC_VIDEO_BRIDGE_H
 #define ANDROID_IARC_VIDEO_BRIDGE_H
 
-#include <arc/IArcBridgeService.h>
+#include <arc/MojoBootstrapResult.h>
 #include <binder/IInterface.h>
 #include <utils/Errors.h>
 
diff --git a/include/android/input.h b/include/android/input.h
index 6810901..cfade6c 100644
--- a/include/android/input.h
+++ b/include/android/input.h
@@ -83,7 +83,7 @@
 };
 
 /**
- * Meta key / modifer state.
+ * Meta key / modifier state.
  */
 enum {
     /** No meta keys are pressed. */
diff --git a/include/input/Input.h b/include/input/Input.h
index cfcafab..7c4379e 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -302,12 +302,18 @@
 
     inline void setSource(int32_t source) { mSource = source; }
 
+    inline int32_t getDisplayId() const { return mDisplayId; }
+
+    inline void setDisplayId(int32_t displayId) { mDisplayId = displayId; }
+
+
 protected:
-    void initialize(int32_t deviceId, int32_t source);
+    void initialize(int32_t deviceId, int32_t source, int32_t displayId);
     void initialize(const InputEvent& from);
 
     int32_t mDeviceId;
     int32_t mSource;
+    int32_t mDisplayId;
 };
 
 /*
@@ -339,10 +345,11 @@
 
     static const char* getLabel(int32_t keyCode);
     static int32_t getKeyCodeFromLabel(const char* label);
-    
+
     void initialize(
             int32_t deviceId,
             int32_t source,
+            int32_t displayId,
             int32_t action,
             int32_t flags,
             int32_t keyCode,
@@ -556,6 +563,7 @@
     void initialize(
             int32_t deviceId,
             int32_t source,
+            int32_t displayId,
             int32_t action,
             int32_t actionButton,
             int32_t flags,
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index 4b33a96..6d072a3 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -326,7 +326,7 @@
     DEFINE_KEYCODE(ALL_APPS),
     DEFINE_KEYCODE(REFRESH),
 
-    { NULL, 0 }
+    { nullptr, 0 }
 };
 
 static const InputEventLabel AXES[] = {
@@ -375,7 +375,7 @@
 
     // NOTE: If you add a new axis here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/MotionEvent.java for the full list.
-    { NULL, 0 }
+    { nullptr, 0 }
 };
 
 static const InputEventLabel LEDS[] = {
@@ -396,7 +396,7 @@
     DEFINE_LED(CONTROLLER_4),
 
     // NOTE: If you add new LEDs here, you must also add them to Input.h
-    { NULL, 0 }
+    { nullptr, 0 }
 };
 
 static const InputEventLabel FLAGS[] = {
@@ -404,7 +404,7 @@
     DEFINE_FLAG(FUNCTION),
     DEFINE_FLAG(GESTURE),
 
-    { NULL, 0 }
+    { nullptr, 0 }
 };
 
 static int lookupValueByLabel(const char* literal, const InputEventLabel *list) {
@@ -424,7 +424,7 @@
         }
         list++;
     }
-    return NULL;
+    return nullptr;
 }
 
 static inline int32_t getKeyCodeByLabel(const char* label) {
@@ -435,7 +435,7 @@
     if (keyCode >= 0 && keyCode < static_cast<int32_t>(size(KEYCODES))) {
         return KEYCODES[keyCode].literal;
     }
-    return NULL;
+    return nullptr;
 }
 
 static inline uint32_t getKeyFlagByLabel(const char* label) {
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 1ea2c2c..e8d1345 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -212,6 +212,7 @@
             uint32_t seq,
             int32_t deviceId,
             int32_t source,
+            int32_t displayId,
             int32_t action,
             int32_t flags,
             int32_t keyCode,
@@ -305,7 +306,7 @@
      * Other errors probably indicate that the channel is broken.
      */
     status_t consume(InputEventFactoryInterface* factory, bool consumeBatches,
-            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId);
+            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
 
     /* Sends a finished signal to the publisher to inform it that the message
      * with the specified sequence number has finished being process and whether
@@ -460,10 +461,9 @@
     Vector<SeqChain> mSeqChains;
 
     status_t consumeBatch(InputEventFactoryInterface* factory,
-            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId);
+            nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent);
     status_t consumeSamples(InputEventFactoryInterface* factory,
-            Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent,
-            int32_t* displayId);
+            Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent);
 
     void updateTouchState(InputMessage& msg);
     void resampleTouchState(nsecs_t frameTime, MotionEvent* event,
diff --git a/include/input/VelocityTracker.h b/include/input/VelocityTracker.h
index ffa1614..727865a 100644
--- a/include/input/VelocityTracker.h
+++ b/include/input/VelocityTracker.h
@@ -63,7 +63,7 @@
 
     // Creates a velocity tracker using the specified strategy.
     // If strategy is NULL, uses the default strategy for the platform.
-    VelocityTracker(const char* strategy = NULL);
+    VelocityTracker(const char* strategy = nullptr);
 
     ~VelocityTracker();
 
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 6a30956..786b136 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -107,6 +107,7 @@
         "-Wall",
         "-Wextra",
         "-Werror",
+        "-Wzero-as-null-pointer-constant",
     ],
     product_variables: {
         binder32bit: {
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index b3ae09b..87c9842 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -74,7 +74,7 @@
 }
 
 // Note: must be kept in sync with android/os/StrictMode.java's PENALTY_GATHER
-#define STRICT_MODE_PENALTY_GATHER (0x40 << 16)
+#define STRICT_MODE_PENALTY_GATHER (1 << 31)
 
 // XXX This can be made public if we want to provide
 // support for typed data.
@@ -2307,6 +2307,15 @@
     int fd = readFileDescriptor();
     if (fd == int(BAD_TYPE)) return BAD_VALUE;
 
+    if (!ashmem_valid(fd)) {
+        ALOGE("invalid fd");
+        return BAD_VALUE;
+    }
+    int size = ashmem_get_size_region(fd);
+    if (size < 0 || size_t(size) < len) {
+        ALOGE("request size %zu does not match fd size %d", len, size);
+        return BAD_VALUE;
+    }
     void* ptr = ::mmap(nullptr, len, isMutable ? PROT_READ | PROT_WRITE : PROT_READ,
             MAP_SHARED, fd, 0);
     if (ptr == MAP_FAILED) return NO_MEMORY;
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index c5b57c7..7870c7b 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -95,6 +95,20 @@
         OP_USE_FINGERPRINT = 55,
         OP_BODY_SENSORS = 56,
         OP_AUDIO_ACCESSIBILITY_VOLUME = 64,
+        OP_READ_PHONE_NUMBERS = 65,
+        OP_REQUEST_INSTALL_PACKAGES = 66,
+        OP_PICTURE_IN_PICTURE = 67,
+        OP_INSTANT_APP_START_FOREGROUND = 68,
+        OP_ANSWER_PHONE_CALLS = 69,
+        OP_RUN_ANY_IN_BACKGROUND = 70,
+        OP_CHANGE_WIFI_STATE = 71,
+        OP_REQUEST_DELETE_PACKAGES = 72,
+        OP_BIND_ACCESSIBILITY_SERVICE = 73,
+        OP_ACCEPT_HANDOVER = 74,
+        OP_MANAGE_IPSEC_TUNNELS = 75,
+        OP_START_FOREGROUND = 76,
+        OP_BLUETOOTH_SCAN = 77,
+        OP_USE_FACE = 78,
     };
 
     AppOpsManager();
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index a998529..1d39aa3 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -86,7 +86,7 @@
     const sp<IServiceManager> sm = defaultServiceManager();
     if (sm != nullptr) {
         *outService = interface_cast<INTERFACE>(sm->getService(name));
-        if ((*outService) != NULL) return NO_ERROR;
+        if ((*outService) != nullptr) return NO_ERROR;
     }
     return NAME_NOT_FOUND;
 }
diff --git a/libs/graphicsenv/GraphicsEnv.cpp b/libs/graphicsenv/GraphicsEnv.cpp
index 961f101..a8ef7a0 100644
--- a/libs/graphicsenv/GraphicsEnv.cpp
+++ b/libs/graphicsenv/GraphicsEnv.cpp
@@ -56,7 +56,7 @@
     mDriverPath = path;
 }
 
-void GraphicsEnv::setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths) {
+void GraphicsEnv::setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths) {
     if (mLayerPaths.empty()) {
         mLayerPaths = layerPaths;
         mAppNamespace = appNamespace;
@@ -66,7 +66,7 @@
     }
 }
 
-android_namespace_t* GraphicsEnv::getAppNamespace() {
+NativeLoaderNamespace* GraphicsEnv::getAppNamespace() {
     return mAppNamespace;
 }
 
diff --git a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
index 213580c..17e8f6b 100644
--- a/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
+++ b/libs/graphicsenv/include/graphicsenv/GraphicsEnv.h
@@ -23,6 +23,8 @@
 
 namespace android {
 
+class NativeLoaderNamespace;
+
 class GraphicsEnv {
 public:
     static GraphicsEnv& getInstance();
@@ -35,8 +37,8 @@
     void setDriverPath(const std::string path);
     android_namespace_t* getDriverNamespace();
 
-    void setLayerPaths(android_namespace_t* appNamespace, const std::string layerPaths);
-    android_namespace_t* getAppNamespace();
+    void setLayerPaths(NativeLoaderNamespace* appNamespace, const std::string layerPaths);
+    NativeLoaderNamespace* getAppNamespace();
     const std::string getLayerPaths();
 
     void setDebugLayers(const std::string layers);
@@ -48,7 +50,7 @@
     std::string mDebugLayers;
     std::string mLayerPaths;
     android_namespace_t* mDriverNamespace = nullptr;
-    android_namespace_t* mAppNamespace = nullptr;
+    NativeLoaderNamespace* mAppNamespace = nullptr;
 };
 
 } // namespace android
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index b29c1d5..ef3e592 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -123,6 +123,7 @@
         "android.hardware.graphics.common@1.1",
         "libsync",
         "libbinder",
+        "libbufferhub",
         "libbufferhubqueue",  // TODO(b/70046255): Remove this once BufferHub is integrated into libgui.
         "libpdx_default_transport",
         "libcutils",
@@ -149,6 +150,7 @@
                 "BufferHubProducer.cpp",
             ],
             exclude_shared_libs: [
+                "libbufferhub",
                 "libbufferhubqueue",
                 "libpdx_default_transport",
             ],
diff --git a/libs/gui/BufferHubProducer.cpp b/libs/gui/BufferHubProducer.cpp
index ae5cca2..06d597c 100644
--- a/libs/gui/BufferHubProducer.cpp
+++ b/libs/gui/BufferHubProducer.cpp
@@ -18,7 +18,9 @@
 #include <gui/BufferHubProducer.h>
 #include <inttypes.h>
 #include <log/log.h>
+#include <private/dvr/detached_buffer.h>
 #include <system/window.h>
+#include <ui/DetachedBufferHandle.h>
 
 namespace android {
 
@@ -224,24 +226,224 @@
     return ret;
 }
 
-status_t BufferHubProducer::detachBuffer(int /* slot */) {
-    ALOGE("BufferHubProducer::detachBuffer not implemented.");
-    return INVALID_OPERATION;
+status_t BufferHubProducer::detachBuffer(int slot) {
+    ALOGV("detachBuffer: slot=%d", slot);
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    return DetachBufferLocked(static_cast<size_t>(slot));
 }
 
-status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* /* out_buffer */,
-                                             sp<Fence>* /* out_fence */) {
-    ALOGE("BufferHubProducer::detachNextBuffer not implemented.");
-    return INVALID_OPERATION;
+status_t BufferHubProducer::DetachBufferLocked(size_t slot) {
+    if (connected_api_ == kNoConnectedApi) {
+        ALOGE("detachBuffer: BufferHubProducer is not connected.");
+        return NO_INIT;
+    }
+
+    if (slot >= static_cast<size_t>(max_buffer_count_)) {
+        ALOGE("detachBuffer: slot index %zu out of range [0, %d)", slot, max_buffer_count_);
+        return BAD_VALUE;
+    } else if (!buffers_[slot].mBufferState.isDequeued()) {
+        ALOGE("detachBuffer: slot %zu is not owned by the producer (state = %s)", slot,
+              buffers_[slot].mBufferState.string());
+        return BAD_VALUE;
+    } else if (!buffers_[slot].mRequestBufferCalled) {
+        ALOGE("detachBuffer: buffer in slot %zu has not been requested", slot);
+        return BAD_VALUE;
+    }
+    std::shared_ptr<BufferProducer> buffer_producer = queue_->GetBuffer(slot);
+    if (buffer_producer == nullptr || buffer_producer->buffer() == nullptr) {
+        ALOGE("detachBuffer: Invalid BufferProducer at slot %zu.", slot);
+        return BAD_VALUE;
+    }
+    sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer();
+    if (graphic_buffer == nullptr) {
+        ALOGE("detachBuffer: Invalid GraphicBuffer at slot %zu.", slot);
+        return BAD_VALUE;
+    }
+
+    // Remove the BufferProducer from the ProducerQueue.
+    status_t error = RemoveBuffer(slot);
+    if (error != NO_ERROR) {
+        ALOGE("detachBuffer: Failed to remove buffer, slot=%zu, error=%d.", slot, error);
+        return error;
+    }
+
+    // Here we need to convert the existing ProducerBuffer into a DetachedBufferHandle and inject
+    // the handle into the GraphicBuffer object at the requested slot.
+    auto status_or_handle = buffer_producer->Detach();
+    if (!status_or_handle.ok()) {
+        ALOGE("detachBuffer: Failed to detach from a BufferProducer at slot %zu, error=%d.", slot,
+              status_or_handle.error());
+        return BAD_VALUE;
+    }
+    std::unique_ptr<DetachedBufferHandle> handle =
+            DetachedBufferHandle::Create(status_or_handle.take());
+    if (!handle->isValid()) {
+        ALOGE("detachBuffer: Failed to create a DetachedBufferHandle at slot %zu.", slot);
+        return BAD_VALUE;
+    }
+
+    return graphic_buffer->setDetachedBufferHandle(std::move(handle));
 }
 
-status_t BufferHubProducer::attachBuffer(int* /* out_slot */,
-                                         const sp<GraphicBuffer>& /* buffer */) {
-    // With this BufferHub backed implementation, we assume (for now) all buffers
-    // are allocated and owned by the BufferHub. Thus the attempt of transfering
-    // ownership of a buffer to the buffer queue is intentionally unsupported.
-    LOG_ALWAYS_FATAL("BufferHubProducer::attachBuffer not supported.");
-    return INVALID_OPERATION;
+status_t BufferHubProducer::detachNextBuffer(sp<GraphicBuffer>* out_buffer, sp<Fence>* out_fence) {
+    ALOGV("detachNextBuffer.");
+
+    if (out_buffer == nullptr || out_fence == nullptr) {
+        ALOGE("detachNextBuffer: Invalid parameter: out_buffer=%p, out_fence=%p", out_buffer,
+              out_fence);
+        return BAD_VALUE;
+    }
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (connected_api_ == kNoConnectedApi) {
+        ALOGE("detachNextBuffer: BufferHubProducer is not connected.");
+        return NO_INIT;
+    }
+
+    // detachNextBuffer is equivalent to calling dequeueBuffer, requestBuffer, and detachBuffer in
+    // sequence, except for two things:
+    //
+    // 1) It is unnecessary to know the dimensions, format, or usage of the next buffer, i.e. the
+    // function just returns whatever BufferProducer is available from the ProducerQueue and no
+    // buffer allocation or re-allocation will happen.
+    // 2) It will not block, since if it cannot find an appropriate buffer to return, it will return
+    // an error instead.
+    size_t slot = 0;
+    LocalHandle fence;
+
+    // First, dequeue a BufferProducer from the ProducerQueue with no timeout. Report error
+    // immediately if ProducerQueue::Dequeue() fails.
+    auto status_or_buffer = queue_->Dequeue(/*timeout=*/0, &slot, &fence);
+    if (!status_or_buffer.ok()) {
+        ALOGE("detachNextBuffer: Failed to dequeue buffer, error=%d.", status_or_buffer.error());
+        return NO_MEMORY;
+    }
+
+    std::shared_ptr<BufferProducer> buffer_producer = status_or_buffer.take();
+    if (buffer_producer == nullptr) {
+        ALOGE("detachNextBuffer: Dequeued buffer is null.");
+        return NO_MEMORY;
+    }
+
+    // With the BufferHub backed solution, slot returned from |queue_->Dequeue| is guaranteed to
+    // be available for producer's use. It's either in free state (if the buffer has never been used
+    // before) or in queued state (if the buffer has been dequeued and queued back to
+    // BufferHubQueue).
+    if (!buffers_[slot].mBufferState.isFree() && !buffers_[slot].mBufferState.isQueued()) {
+        ALOGE("detachNextBuffer: slot %zu is not free or queued, actual state: %s.", slot,
+              buffers_[slot].mBufferState.string());
+        return BAD_VALUE;
+    }
+    if (buffers_[slot].mBufferProducer == nullptr) {
+        ALOGE("detachNextBuffer: BufferProducer at slot %zu is null.", slot);
+        return BAD_VALUE;
+    }
+    if (buffers_[slot].mBufferProducer->id() != buffer_producer->id()) {
+        ALOGE("detachNextBuffer: BufferProducer at slot %zu has mismatched id, actual: "
+              "%d, expected: %d.",
+              slot, buffers_[slot].mBufferProducer->id(), buffer_producer->id());
+        return BAD_VALUE;
+    }
+
+    ALOGV("detachNextBuffer: slot=%zu", slot);
+    buffers_[slot].mBufferState.freeQueued();
+    buffers_[slot].mBufferState.dequeue();
+
+    // Second, request the buffer.
+    sp<GraphicBuffer> graphic_buffer = buffer_producer->buffer()->buffer();
+    buffers_[slot].mGraphicBuffer = buffer_producer->buffer()->buffer();
+
+    // Finally, detach the buffer and then return.
+    status_t error = DetachBufferLocked(slot);
+    if (error == NO_ERROR) {
+        *out_fence = new Fence(fence.Release());
+        *out_buffer = graphic_buffer;
+    }
+    return error;
+}
+
+status_t BufferHubProducer::attachBuffer(int* out_slot, const sp<GraphicBuffer>& buffer) {
+    // In the BufferHub design, all buffers are allocated and owned by the BufferHub. Thus only
+    // GraphicBuffers that are originated from BufferHub can be attached to a BufferHubProducer.
+    ALOGV("queueBuffer: buffer=%p", buffer.get());
+
+    if (out_slot == nullptr) {
+        ALOGE("attachBuffer: out_slot cannot be NULL.");
+        return BAD_VALUE;
+    }
+    if (buffer == nullptr || !buffer->isDetachedBuffer()) {
+        ALOGE("attachBuffer: invalid GraphicBuffer.");
+        return BAD_VALUE;
+    }
+
+    std::unique_lock<std::mutex> lock(mutex_);
+
+    if (connected_api_ == kNoConnectedApi) {
+        ALOGE("attachBuffer: BufferQueue has no connected producer");
+        return NO_INIT;
+    }
+
+    // Before attaching the buffer, caller is supposed to call
+    // IGraphicBufferProducer::setGenerationNumber to inform the
+    // BufferHubProducer the next generation number.
+    if (buffer->getGenerationNumber() != generation_number_) {
+        ALOGE("attachBuffer: Mismatched generation number, buffer: %u, queue: %u.",
+              buffer->getGenerationNumber(), generation_number_);
+        return BAD_VALUE;
+    }
+
+    // Creates a BufferProducer from the GraphicBuffer.
+    std::unique_ptr<DetachedBufferHandle> detached_handle = buffer->takeDetachedBufferHandle();
+    if (detached_handle == nullptr) {
+        ALOGE("attachBuffer: DetachedBufferHandle cannot be NULL.");
+        return BAD_VALUE;
+    }
+    auto detached_buffer = DetachedBuffer::Import(std::move(detached_handle->handle()));
+    if (detached_buffer == nullptr) {
+        ALOGE("attachBuffer: DetachedBuffer cannot be NULL.");
+        return BAD_VALUE;
+    }
+    auto status_or_handle = detached_buffer->Promote();
+    if (!status_or_handle.ok()) {
+        ALOGE("attachBuffer: Failed to promote a DetachedBuffer into a BufferProducer, error=%d.",
+              status_or_handle.error());
+        return BAD_VALUE;
+    }
+    std::shared_ptr<BufferProducer> buffer_producer =
+            BufferProducer::Import(status_or_handle.take());
+    if (buffer_producer == nullptr) {
+        ALOGE("attachBuffer: Failed to import BufferProducer.");
+        return BAD_VALUE;
+    }
+
+    // Adds the BufferProducer into the Queue.
+    auto status_or_slot = queue_->InsertBuffer(buffer_producer);
+    if (!status_or_slot.ok()) {
+        ALOGE("attachBuffer: Failed to insert buffer, error=%d.", status_or_slot.error());
+        return BAD_VALUE;
+    }
+
+    size_t slot = status_or_slot.get();
+    ALOGV("attachBuffer: returning slot %zu.", slot);
+    if (slot >= static_cast<size_t>(max_buffer_count_)) {
+        ALOGE("attachBuffer: Invalid slot: %zu.", slot);
+        return BAD_VALUE;
+    }
+
+    // The just attached buffer should be in dequeued state according to IGraphicBufferProducer
+    // interface. In BufferHub's language the buffer should be in Gained state.
+    buffers_[slot].mGraphicBuffer = buffer;
+    buffers_[slot].mBufferState.attachProducer();
+    buffers_[slot].mEglFence = EGL_NO_SYNC_KHR;
+    buffers_[slot].mFence = Fence::NO_FENCE;
+    buffers_[slot].mRequestBufferCalled = true;
+    buffers_[slot].mAcquireCalled = false;
+    buffers_[slot].mNeedsReallocation = false;
+
+    *out_slot = static_cast<int>(slot);
+    return NO_ERROR;
 }
 
 status_t BufferHubProducer::queueBuffer(int slot, const QueueBufferInput& input,
@@ -654,26 +856,28 @@
 status_t BufferHubProducer::RemoveBuffer(size_t slot) {
     auto status = queue_->RemoveBuffer(slot);
     if (!status) {
-        ALOGE("BufferHubProducer::RemoveBuffer: Failed to remove buffer: %s",
-              status.GetErrorMessage().c_str());
+        ALOGE("BufferHubProducer::RemoveBuffer: Failed to remove buffer at slot: %zu, error: %s.",
+              slot, status.GetErrorMessage().c_str());
         return INVALID_OPERATION;
     }
 
     // Reset in memory objects related the the buffer.
     buffers_[slot].mBufferProducer = nullptr;
-    buffers_[slot].mGraphicBuffer = nullptr;
     buffers_[slot].mBufferState.detachProducer();
+    buffers_[slot].mFence = Fence::NO_FENCE;
+    buffers_[slot].mGraphicBuffer = nullptr;
+    buffers_[slot].mRequestBufferCalled = false;
     return NO_ERROR;
 }
 
 status_t BufferHubProducer::FreeAllBuffers() {
     for (size_t slot = 0; slot < BufferHubQueue::kMaxQueueCapacity; slot++) {
         // Reset in memory objects related the the buffer.
-        buffers_[slot].mGraphicBuffer = nullptr;
-        buffers_[slot].mBufferState.reset();
-        buffers_[slot].mRequestBufferCalled = false;
         buffers_[slot].mBufferProducer = nullptr;
+        buffers_[slot].mBufferState.reset();
         buffers_[slot].mFence = Fence::NO_FENCE;
+        buffers_[slot].mGraphicBuffer = nullptr;
+        buffers_[slot].mRequestBufferCalled = false;
     }
 
     auto status = queue_->FreeAllBuffers();
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index f50379b..5beba02 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -39,8 +39,8 @@
 }
 
 BufferItem::BufferItem() :
-    mGraphicBuffer(NULL),
-    mFence(NULL),
+    mGraphicBuffer(nullptr),
+    mFence(nullptr),
     mCrop(Rect::INVALID_RECT),
     mTransform(0),
     mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
@@ -91,11 +91,11 @@
 
 size_t BufferItem::getFlattenedSize() const {
     size_t size = sizeof(uint32_t); // Flags
-    if (mGraphicBuffer != 0) {
+    if (mGraphicBuffer != nullptr) {
         size += mGraphicBuffer->getFlattenedSize();
         size = FlattenableUtils::align<4>(size);
     }
-    if (mFence != 0) {
+    if (mFence != nullptr) {
         size += mFence->getFlattenedSize();
         size = FlattenableUtils::align<4>(size);
     }
@@ -107,10 +107,10 @@
 
 size_t BufferItem::getFdCount() const {
     size_t count = 0;
-    if (mGraphicBuffer != 0) {
+    if (mGraphicBuffer != nullptr) {
         count += mGraphicBuffer->getFdCount();
     }
-    if (mFence != 0) {
+    if (mFence != nullptr) {
         count += mFence->getFdCount();
     }
     return count;
@@ -137,13 +137,13 @@
     FlattenableUtils::advance(buffer, size, sizeof(uint32_t));
 
     flags = 0;
-    if (mGraphicBuffer != 0) {
+    if (mGraphicBuffer != nullptr) {
         status_t err = mGraphicBuffer->flatten(buffer, size, fds, count);
         if (err) return err;
         size -= FlattenableUtils::align<4>(buffer);
         flags |= 1;
     }
-    if (mFence != 0) {
+    if (mFence != nullptr) {
         status_t err = mFence->flatten(buffer, size, fds, count);
         if (err) return err;
         size -= FlattenableUtils::align<4>(buffer);
diff --git a/libs/gui/BufferItemConsumer.cpp b/libs/gui/BufferItemConsumer.cpp
index 89bc0c4..f50bc20 100644
--- a/libs/gui/BufferItemConsumer.cpp
+++ b/libs/gui/BufferItemConsumer.cpp
@@ -107,7 +107,7 @@
 
 void BufferItemConsumer::freeBufferLocked(int slotIndex) {
     sp<BufferFreedListener> listener = mBufferFreedListener.promote();
-    if (listener != NULL && mSlots[slotIndex].mGraphicBuffer != NULL) {
+    if (listener != nullptr && mSlots[slotIndex].mGraphicBuffer != nullptr) {
         // Fire callback if we have a listener registered and the buffer being freed is valid.
         BI_LOGV("actually calling onBufferFreed");
         listener->onBufferFreed(mSlots[slotIndex].mGraphicBuffer);
diff --git a/libs/gui/BufferQueue.cpp b/libs/gui/BufferQueue.cpp
index a8da134..5fb3f0b 100644
--- a/libs/gui/BufferQueue.cpp
+++ b/libs/gui/BufferQueue.cpp
@@ -38,7 +38,7 @@
 
 void BufferQueue::ProxyConsumerListener::onDisconnect() {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onDisconnect();
     }
 }
@@ -46,7 +46,7 @@
 void BufferQueue::ProxyConsumerListener::onFrameAvailable(
         const BufferItem& item) {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onFrameAvailable(item);
     }
 }
@@ -54,21 +54,21 @@
 void BufferQueue::ProxyConsumerListener::onFrameReplaced(
         const BufferItem& item) {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onFrameReplaced(item);
     }
 }
 
 void BufferQueue::ProxyConsumerListener::onBuffersReleased() {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBuffersReleased();
     }
 }
 
 void BufferQueue::ProxyConsumerListener::onSidebandStreamChanged() {
     sp<ConsumerListener> listener(mConsumerListener.promote());
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onSidebandStreamChanged();
     }
 }
@@ -85,21 +85,21 @@
 void BufferQueue::createBufferQueue(sp<IGraphicBufferProducer>* outProducer,
         sp<IGraphicBufferConsumer>* outConsumer,
         bool consumerIsSurfaceFlinger) {
-    LOG_ALWAYS_FATAL_IF(outProducer == NULL,
+    LOG_ALWAYS_FATAL_IF(outProducer == nullptr,
             "BufferQueue: outProducer must not be NULL");
-    LOG_ALWAYS_FATAL_IF(outConsumer == NULL,
+    LOG_ALWAYS_FATAL_IF(outConsumer == nullptr,
             "BufferQueue: outConsumer must not be NULL");
 
     sp<BufferQueueCore> core(new BufferQueueCore());
-    LOG_ALWAYS_FATAL_IF(core == NULL,
+    LOG_ALWAYS_FATAL_IF(core == nullptr,
             "BufferQueue: failed to create BufferQueueCore");
 
     sp<IGraphicBufferProducer> producer(new BufferQueueProducer(core, consumerIsSurfaceFlinger));
-    LOG_ALWAYS_FATAL_IF(producer == NULL,
+    LOG_ALWAYS_FATAL_IF(producer == nullptr,
             "BufferQueue: failed to create BufferQueueProducer");
 
     sp<IGraphicBufferConsumer> consumer(new BufferQueueConsumer(core));
-    LOG_ALWAYS_FATAL_IF(consumer == NULL,
+    LOG_ALWAYS_FATAL_IF(consumer == nullptr,
             "BufferQueue: failed to create BufferQueueConsumer");
 
     *outProducer = producer;
@@ -109,8 +109,8 @@
 #ifndef NO_BUFFERHUB
 void BufferQueue::createBufferHubQueue(sp<IGraphicBufferProducer>* outProducer,
                                        sp<IGraphicBufferConsumer>* outConsumer) {
-    LOG_ALWAYS_FATAL_IF(outProducer == NULL, "BufferQueue: outProducer must not be NULL");
-    LOG_ALWAYS_FATAL_IF(outConsumer == NULL, "BufferQueue: outConsumer must not be NULL");
+    LOG_ALWAYS_FATAL_IF(outProducer == nullptr, "BufferQueue: outProducer must not be NULL");
+    LOG_ALWAYS_FATAL_IF(outConsumer == nullptr, "BufferQueue: outConsumer must not be NULL");
 
     sp<IGraphicBufferProducer> producer;
     sp<IGraphicBufferConsumer> consumer;
@@ -118,16 +118,16 @@
     dvr::ProducerQueueConfigBuilder configBuilder;
     std::shared_ptr<dvr::ProducerQueue> producerQueue =
             dvr::ProducerQueue::Create(configBuilder.Build(), dvr::UsagePolicy{});
-    LOG_ALWAYS_FATAL_IF(producerQueue == NULL, "BufferQueue: failed to create ProducerQueue.");
+    LOG_ALWAYS_FATAL_IF(producerQueue == nullptr, "BufferQueue: failed to create ProducerQueue.");
 
     std::shared_ptr<dvr::ConsumerQueue> consumerQueue = producerQueue->CreateConsumerQueue();
-    LOG_ALWAYS_FATAL_IF(consumerQueue == NULL, "BufferQueue: failed to create ConsumerQueue.");
+    LOG_ALWAYS_FATAL_IF(consumerQueue == nullptr, "BufferQueue: failed to create ConsumerQueue.");
 
     producer = BufferHubProducer::Create(producerQueue);
     consumer = BufferHubConsumer::Create(consumerQueue);
 
-    LOG_ALWAYS_FATAL_IF(producer == NULL, "BufferQueue: failed to create BufferQueueProducer");
-    LOG_ALWAYS_FATAL_IF(consumer == NULL, "BufferQueue: failed to create BufferQueueConsumer");
+    LOG_ALWAYS_FATAL_IF(producer == nullptr, "BufferQueue: failed to create BufferQueueProducer");
+    LOG_ALWAYS_FATAL_IF(consumer == nullptr, "BufferQueue: failed to create BufferQueueConsumer");
 
     *outProducer = producer;
     *outConsumer = consumer;
diff --git a/libs/gui/BufferQueueConsumer.cpp b/libs/gui/BufferQueueConsumer.cpp
index d70e142..3837c3e 100644
--- a/libs/gui/BufferQueueConsumer.cpp
+++ b/libs/gui/BufferQueueConsumer.cpp
@@ -255,7 +255,7 @@
         // mGraphicBuffer to NULL to avoid unnecessarily remapping this buffer
         // on the consumer side
         if (outBuffer->mAcquireCalled) {
-            outBuffer->mGraphicBuffer = NULL;
+            outBuffer->mGraphicBuffer = nullptr;
         }
 
         mCore->mQueue.erase(front);
@@ -272,7 +272,7 @@
         VALIDATE_CONSISTENCY();
     }
 
-    if (listener != NULL) {
+    if (listener != nullptr) {
         for (int i = 0; i < numDroppedBuffers; ++i) {
             listener->onBufferReleased();
         }
@@ -321,10 +321,10 @@
         const sp<android::GraphicBuffer>& buffer) {
     ATRACE_CALL();
 
-    if (outSlot == NULL) {
+    if (outSlot == nullptr) {
         BQ_LOGE("attachBuffer: outSlot must not be NULL");
         return BAD_VALUE;
-    } else if (buffer == NULL) {
+    } else if (buffer == nullptr) {
         BQ_LOGE("attachBuffer: cannot attach NULL buffer");
         return BAD_VALUE;
     }
@@ -413,7 +413,7 @@
     ATRACE_BUFFER_INDEX(slot);
 
     if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS ||
-            releaseFence == NULL) {
+            releaseFence == nullptr) {
         BQ_LOGE("releaseBuffer: slot %d out of range or fence %p NULL", slot,
                 releaseFence.get());
         return BAD_VALUE;
@@ -465,7 +465,7 @@
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBufferReleased();
     }
 
@@ -476,7 +476,7 @@
         const sp<IConsumerListener>& consumerListener, bool controlledByApp) {
     ATRACE_CALL();
 
-    if (consumerListener == NULL) {
+    if (consumerListener == nullptr) {
         BQ_LOGE("connect: consumerListener may not be NULL");
         return BAD_VALUE;
     }
@@ -504,13 +504,13 @@
 
     Mutex::Autolock lock(mCore->mMutex);
 
-    if (mCore->mConsumerListener == NULL) {
+    if (mCore->mConsumerListener == nullptr) {
         BQ_LOGE("disconnect: no consumer is connected");
         return BAD_VALUE;
     }
 
     mCore->mIsAbandoned = true;
-    mCore->mConsumerListener = NULL;
+    mCore->mConsumerListener = nullptr;
     mCore->mQueue.clear();
     mCore->freeAllBuffersLocked();
     mCore->mSharedBufferSlot = BufferQueueCore::INVALID_BUFFER_SLOT;
@@ -521,7 +521,7 @@
 status_t BufferQueueConsumer::getReleasedBuffers(uint64_t *outSlotMask) {
     ATRACE_CALL();
 
-    if (outSlotMask == NULL) {
+    if (outSlotMask == nullptr) {
         BQ_LOGE("getReleasedBuffers: outSlotMask may not be NULL");
         return BAD_VALUE;
     }
@@ -673,7 +673,7 @@
         }
     }
     // Call back without lock held
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBuffersReleased();
     }
 
@@ -772,7 +772,7 @@
     if (uid != shellUid) {
 #endif
         android_errorWriteWithInfoLog(0x534e4554, "27046057",
-                static_cast<int32_t>(uid), NULL, 0);
+                static_cast<int32_t>(uid), nullptr, 0);
         return PERMISSION_DENIED;
     }
 
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index bb703da..960b194 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -349,7 +349,7 @@
                 BQ_LOGE("Slot %d is in mUnusedSlots but is not FREE", slot);
                 usleep(PAUSE_TIME);
             }
-            if (mSlots[slot].mGraphicBuffer != NULL) {
+            if (mSlots[slot].mGraphicBuffer != nullptr) {
                 BQ_LOGE("Slot %d is in mUnusedSluts but has an active buffer",
                         slot);
                 usleep(PAUSE_TIME);
@@ -371,7 +371,7 @@
                 BQ_LOGE("Slot %d is in mFreeSlots but is not FREE", slot);
                 usleep(PAUSE_TIME);
             }
-            if (mSlots[slot].mGraphicBuffer != NULL) {
+            if (mSlots[slot].mGraphicBuffer != nullptr) {
                 BQ_LOGE("Slot %d is in mFreeSlots but has a buffer",
                         slot);
                 usleep(PAUSE_TIME);
@@ -394,7 +394,7 @@
                 BQ_LOGE("Slot %d is in mFreeBuffers but is not FREE", slot);
                 usleep(PAUSE_TIME);
             }
-            if (mSlots[slot].mGraphicBuffer == NULL) {
+            if (mSlots[slot].mGraphicBuffer == nullptr) {
                 BQ_LOGE("Slot %d is in mFreeBuffers but has no buffer", slot);
                 usleep(PAUSE_TIME);
             }
@@ -418,7 +418,7 @@
                 BQ_LOGE("Slot %d is in mActiveBuffers but is FREE", slot);
                 usleep(PAUSE_TIME);
             }
-            if (mSlots[slot].mGraphicBuffer == NULL && !mIsAllocating) {
+            if (mSlots[slot].mGraphicBuffer == nullptr && !mIsAllocating) {
                 BQ_LOGE("Slot %d is in mActiveBuffers but has no buffer", slot);
                 usleep(PAUSE_TIME);
             }
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index c96a2dd..5e250a4 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -166,7 +166,7 @@
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBuffersReleased();
     }
 
@@ -221,7 +221,7 @@
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBuffersReleased();
     }
     return NO_ERROR;
@@ -449,11 +449,11 @@
 
         mSlots[found].mBufferState.dequeue();
 
-        if ((buffer == NULL) ||
+        if ((buffer == nullptr) ||
                 buffer->needsReallocation(width, height, format, BQ_LAYER_COUNT, usage))
         {
             mSlots[found].mAcquireCalled = false;
-            mSlots[found].mGraphicBuffer = NULL;
+            mSlots[found].mGraphicBuffer = nullptr;
             mSlots[found].mRequestBufferCalled = false;
             mSlots[found].mEglDisplay = EGL_NO_DISPLAY;
             mSlots[found].mEglFence = EGL_NO_SYNC_KHR;
@@ -471,7 +471,7 @@
         BQ_LOGV("dequeueBuffer: setting buffer age to %" PRIu64,
                 mCore->mBufferAge);
 
-        if (CC_UNLIKELY(mSlots[found].mFence == NULL)) {
+        if (CC_UNLIKELY(mSlots[found].mFence == nullptr)) {
             BQ_LOGE("dequeueBuffer: about to return a NULL fence - "
                     "slot=%d w=%d h=%d format=%u",
                     found, buffer->width, buffer->height, buffer->format);
@@ -612,7 +612,7 @@
         listener = mCore->mConsumerListener;
     }
 
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBuffersReleased();
     }
 
@@ -623,10 +623,10 @@
         sp<Fence>* outFence) {
     ATRACE_CALL();
 
-    if (outBuffer == NULL) {
+    if (outBuffer == nullptr) {
         BQ_LOGE("detachNextBuffer: outBuffer must not be NULL");
         return BAD_VALUE;
-    } else if (outFence == NULL) {
+    } else if (outFence == nullptr) {
         BQ_LOGE("detachNextBuffer: outFence must not be NULL");
         return BAD_VALUE;
     }
@@ -670,7 +670,7 @@
         listener = mCore->mConsumerListener;
     }
 
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBuffersReleased();
     }
 
@@ -681,10 +681,10 @@
         const sp<android::GraphicBuffer>& buffer) {
     ATRACE_CALL();
 
-    if (outSlot == NULL) {
+    if (outSlot == nullptr) {
         BQ_LOGE("attachBuffer: outSlot must not be NULL");
         return BAD_VALUE;
-    } else if (buffer == NULL) {
+    } else if (buffer == nullptr) {
         BQ_LOGE("attachBuffer: cannot attach NULL buffer");
         return BAD_VALUE;
     }
@@ -766,7 +766,7 @@
     const Region& surfaceDamage = input.getSurfaceDamage();
     const HdrMetadata& hdrMetadata = input.getHdrMetadata();
 
-    if (acquireFence == NULL) {
+    if (acquireFence == nullptr) {
         BQ_LOGE("queueBuffer: fence is NULL");
         return BAD_VALUE;
     }
@@ -972,9 +972,9 @@
             mCallbackCondition.wait(mCallbackMutex);
         }
 
-        if (frameAvailableListener != NULL) {
+        if (frameAvailableListener != nullptr) {
             frameAvailableListener->onFrameAvailable(item);
-        } else if (frameReplacedListener != NULL) {
+        } else if (frameReplacedListener != nullptr) {
             frameReplacedListener->onFrameReplaced(item);
         }
 
@@ -1039,7 +1039,7 @@
         BQ_LOGE("cancelBuffer: slot %d is not owned by the producer "
                 "(state = %s)", slot, mSlots[slot].mBufferState.string());
         return BAD_VALUE;
-    } else if (fence == NULL) {
+    } else if (fence == nullptr) {
         BQ_LOGE("cancelBuffer: fence is NULL");
         return BAD_VALUE;
     }
@@ -1069,7 +1069,7 @@
     ATRACE_CALL();
     Mutex::Autolock lock(mCore->mMutex);
 
-    if (outValue == NULL) {
+    if (outValue == nullptr) {
         BQ_LOGE("query: outValue was NULL");
         return BAD_VALUE;
     }
@@ -1145,12 +1145,12 @@
         return NO_INIT;
     }
 
-    if (mCore->mConsumerListener == NULL) {
+    if (mCore->mConsumerListener == nullptr) {
         BQ_LOGE("connect: BufferQueue has no consumer");
         return NO_INIT;
     }
 
-    if (output == NULL) {
+    if (output == nullptr) {
         BQ_LOGE("connect: output was NULL");
         return BAD_VALUE;
     }
@@ -1188,10 +1188,10 @@
             output->nextFrameNumber = mCore->mFrameCounter + 1;
             output->bufferReplaced = false;
 
-            if (listener != NULL) {
+            if (listener != nullptr) {
                 // Set up a death notification so that we can disconnect
                 // automatically if the remote producer dies
-                if (IInterface::asBinder(listener)->remoteBinder() != NULL) {
+                if (IInterface::asBinder(listener)->remoteBinder() != nullptr) {
                     status = IInterface::asBinder(listener)->linkToDeath(
                             static_cast<IBinder::DeathRecipient*>(this));
                     if (status != NO_ERROR) {
@@ -1268,7 +1268,7 @@
                     mCore->freeAllBuffersLocked();
 
                     // Remove our death notification callback if we have one
-                    if (mCore->mLinkedToDeath != NULL) {
+                    if (mCore->mLinkedToDeath != nullptr) {
                         sp<IBinder> token =
                                 IInterface::asBinder(mCore->mLinkedToDeath);
                         // This can fail if we're here because of the death
@@ -1278,8 +1278,8 @@
                     }
                     mCore->mSharedBufferSlot =
                             BufferQueueCore::INVALID_BUFFER_SLOT;
-                    mCore->mLinkedToDeath = NULL;
-                    mCore->mConnectedProducerListener = NULL;
+                    mCore->mLinkedToDeath = nullptr;
+                    mCore->mConnectedProducerListener = nullptr;
                     mCore->mConnectedApi = BufferQueueCore::NO_CONNECTED_API;
                     mCore->mConnectedPid = -1;
                     mCore->mSidebandStream.clear();
@@ -1302,7 +1302,7 @@
     } // Autolock scope
 
     // Call back without lock held
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onBuffersReleased();
         listener->onDisconnect();
     }
@@ -1318,7 +1318,7 @@
         listener = mCore->mConsumerListener;
     } // Autolock scope
 
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->onSidebandStreamChanged();
     }
     return NO_ERROR;
@@ -1536,7 +1536,7 @@
         Mutex::Autolock lock(mCore->mMutex);
         listener = mCore->mConsumerListener;
     }
-    if (listener != NULL) {
+    if (listener != nullptr) {
         listener->addAndGetFrameTimestamps(newTimestamps, outDelta);
     }
 }
diff --git a/libs/gui/ConsumerBase.cpp b/libs/gui/ConsumerBase.cpp
index f9e292e..abd9921 100644
--- a/libs/gui/ConsumerBase.cpp
+++ b/libs/gui/ConsumerBase.cpp
@@ -96,7 +96,7 @@
 
 void ConsumerBase::freeBufferLocked(int slotIndex) {
     CB_LOGV("freeBufferLocked: slotIndex=%d", slotIndex);
-    mSlots[slotIndex].mGraphicBuffer = 0;
+    mSlots[slotIndex].mGraphicBuffer = nullptr;
     mSlots[slotIndex].mFence = Fence::NO_FENCE;
     mSlots[slotIndex].mFrameNumber = 0;
 }
@@ -110,7 +110,7 @@
         listener = mFrameAvailableListener.promote();
     }
 
-    if (listener != NULL) {
+    if (listener != nullptr) {
         CB_LOGV("actually calling onFrameAvailable");
         listener->onFrameAvailable(item);
     }
@@ -125,7 +125,7 @@
         listener = mFrameAvailableListener.promote();
     }
 
-    if (listener != NULL) {
+    if (listener != nullptr) {
         CB_LOGV("actually calling onFrameReplaced");
         listener->onFrameReplaced(item);
     }
@@ -352,8 +352,8 @@
         return err;
     }
 
-    if (item->mGraphicBuffer != NULL) {
-        if (mSlots[item->mSlot].mGraphicBuffer != NULL) {
+    if (item->mGraphicBuffer != nullptr) {
+        if (mSlots[item->mSlot].mGraphicBuffer != nullptr) {
             freeBufferLocked(item->mSlot);
         }
         mSlots[item->mSlot].mGraphicBuffer = item->mGraphicBuffer;
@@ -468,7 +468,7 @@
     if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) {
         return false;
     }
-    return (mSlots[slot].mGraphicBuffer != NULL &&
+    return (mSlots[slot].mGraphicBuffer != nullptr &&
             mSlots[slot].mGraphicBuffer->handle == graphicBuffer->handle);
 }
 
diff --git a/libs/gui/DisplayEventReceiver.cpp b/libs/gui/DisplayEventReceiver.cpp
index 1757ec1..f5cf1c4 100644
--- a/libs/gui/DisplayEventReceiver.cpp
+++ b/libs/gui/DisplayEventReceiver.cpp
@@ -34,9 +34,9 @@
 
 DisplayEventReceiver::DisplayEventReceiver(ISurfaceComposer::VsyncSource vsyncSource) {
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    if (sf != NULL) {
+    if (sf != nullptr) {
         mEventConnection = sf->createDisplayEventConnection(vsyncSource);
-        if (mEventConnection != NULL) {
+        if (mEventConnection != nullptr) {
             mDataChannel = std::make_unique<gui::BitTube>();
             mEventConnection->stealReceiveChannel(mDataChannel.get());
         }
@@ -47,13 +47,13 @@
 }
 
 status_t DisplayEventReceiver::initCheck() const {
-    if (mDataChannel != NULL)
+    if (mDataChannel != nullptr)
         return NO_ERROR;
     return NO_INIT;
 }
 
 int DisplayEventReceiver::getFd() const {
-    if (mDataChannel == NULL)
+    if (mDataChannel == nullptr)
         return NO_INIT;
 
     return mDataChannel->getFd();
@@ -63,7 +63,7 @@
     if (int32_t(count) < 0)
         return BAD_VALUE;
 
-    if (mEventConnection != NULL) {
+    if (mEventConnection != nullptr) {
         mEventConnection->setVsyncRate(count);
         return NO_ERROR;
     }
@@ -71,7 +71,7 @@
 }
 
 status_t DisplayEventReceiver::requestNextVsync() {
-    if (mEventConnection != NULL) {
+    if (mEventConnection != nullptr) {
         mEventConnection->requestNextVsync();
         return NO_ERROR;
     }
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 885efec..5532db4 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -46,7 +46,6 @@
 #include <utils/Trace.h>
 
 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-#define CROP_EXT_STR "EGL_ANDROID_image_crop"
 #define PROT_CONTENT_EXT_STR "EGL_EXT_protected_content"
 #define EGL_PROTECTED_CONTENT_EXT 0x32C0
 
@@ -82,26 +81,6 @@
 Mutex GLConsumer::sStaticInitLock;
 sp<GraphicBuffer> GLConsumer::sReleasedTexImageBuffer;
 
-static bool hasEglAndroidImageCropImpl() {
-    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
-    size_t cropExtLen = strlen(CROP_EXT_STR);
-    size_t extsLen = strlen(exts);
-    bool equal = !strcmp(CROP_EXT_STR, exts);
-    bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
-    bool atEnd = (cropExtLen+1) < extsLen &&
-            !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
-    bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
-    return equal || atStart || atEnd || inMiddle;
-}
-
-static bool hasEglAndroidImageCrop() {
-    // Only compute whether the extension is present once the first time this
-    // function is called.
-    static bool hasIt = hasEglAndroidImageCropImpl();
-    return hasIt;
-}
-
 static bool hasEglProtectedContentImpl() {
     EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     const char* exts = eglQueryString(dpy, EGL_EXTENSIONS);
@@ -122,10 +101,6 @@
     return hasIt;
 }
 
-static bool isEglImageCroppable(const Rect& crop) {
-    return hasEglAndroidImageCrop() && (crop.left == 0 && crop.top == 0);
-}
-
 GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
         uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
     ConsumerBase(bq, isControlledByApp),
@@ -291,7 +266,7 @@
             return err;
         }
 
-        if (mReleasedTexImage == NULL) {
+        if (mReleasedTexImage == nullptr) {
             mReleasedTexImage = new EglImage(getDebugTexImageBuffer());
         }
 
@@ -321,7 +296,7 @@
 
 sp<GraphicBuffer> GLConsumer::getDebugTexImageBuffer() {
     Mutex::Autolock _l(sStaticInitLock);
-    if (CC_UNLIKELY(sReleasedTexImageBuffer == NULL)) {
+    if (CC_UNLIKELY(sReleasedTexImageBuffer == nullptr)) {
         // The first time, create the debug texture in case the application
         // continues to use it.
         sp<GraphicBuffer> buffer = new GraphicBuffer(
@@ -357,7 +332,7 @@
     // If item->mGraphicBuffer is not null, this buffer has not been acquired
     // before, so any prior EglImage created is using a stale buffer. This
     // replaces any old EglImage with a new one (using the new buffer).
-    if (item->mGraphicBuffer != NULL) {
+    if (item->mGraphicBuffer != nullptr) {
         int slot = item->mSlot;
         mEglSlots[slot].mEglImage = new EglImage(item->mGraphicBuffer);
     }
@@ -406,7 +381,7 @@
     // ConsumerBase.
     // We may have to do this even when item.mGraphicBuffer == NULL (which
     // means the buffer was previously acquired).
-    err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay, item.mCrop);
+    err = mEglSlots[slot].mEglImage->createIfNeeded(mEglDisplay);
     if (err != NO_ERROR) {
         GLC_LOGW("updateAndRelease: unable to createImage on display=%p slot=%d",
                 mEglDisplay, slot);
@@ -430,8 +405,8 @@
     }
 
     GLC_LOGV("updateAndRelease: (slot=%d buf=%p) -> (slot=%d buf=%p)",
-            mCurrentTexture, mCurrentTextureImage != NULL ?
-                    mCurrentTextureImage->graphicBufferHandle() : 0,
+            mCurrentTexture, mCurrentTextureImage != nullptr ?
+                    mCurrentTextureImage->graphicBufferHandle() : nullptr,
             slot, mSlots[slot].mGraphicBuffer->handle);
 
     // Hang onto the pointer so that it isn't freed in the call to
@@ -491,13 +466,12 @@
 
     glBindTexture(mTexTarget, mTexName);
     if (mCurrentTexture == BufferQueue::INVALID_BUFFER_SLOT &&
-            mCurrentTextureImage == NULL) {
+            mCurrentTextureImage == nullptr) {
         GLC_LOGE("bindTextureImage: no currently-bound texture");
         return NO_INIT;
     }
 
-    status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
-                                                        mCurrentCrop);
+    status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay);
     if (err != NO_ERROR) {
         GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
                 mEglDisplay, mCurrentTexture);
@@ -511,9 +485,7 @@
     // forcing the creation of a new image.
     if ((error = glGetError()) != GL_NO_ERROR) {
         glBindTexture(mTexTarget, mTexName);
-        status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay,
-                                                               mCurrentCrop,
-                                                               true);
+        status_t result = mCurrentTextureImage->createIfNeeded(mEglDisplay, true);
         if (result != NO_ERROR) {
             GLC_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
                     mEglDisplay, mCurrentTexture);
@@ -655,7 +627,7 @@
     mTexName = tex;
     mAttached = true;
 
-    if (mCurrentTextureImage != NULL) {
+    if (mCurrentTextureImage != nullptr) {
         // This may wait for a buffer a second time. This is likely required if
         // this is a different context, since otherwise the wait could be skipped
         // by bouncing through another context. For the same context the extra
@@ -676,7 +648,7 @@
     if (mCurrentTexture != BufferQueue::INVALID_BUFFER_SLOT) {
         if (SyncFeatures::getInstance().useNativeFenceSync()) {
             EGLSyncKHR sync = eglCreateSyncKHR(dpy,
-                    EGL_SYNC_NATIVE_FENCE_ANDROID, NULL);
+                    EGL_SYNC_NATIVE_FENCE_ANDROID, nullptr);
             if (sync == EGL_NO_SYNC_KHR) {
                 GLC_LOGE("syncForReleaseLocked: error creating EGL fence: %#x",
                         eglGetError());
@@ -720,7 +692,7 @@
 
             // Create a fence for the outstanding accesses in the current
             // OpenGL ES context.
-            fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
+            fence = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
             if (fence == EGL_NO_SYNC_KHR) {
                 GLC_LOGE("syncForReleaseLocked: error creating fence: %#x",
                         eglGetError());
@@ -752,11 +724,11 @@
     bool needsRecompute = mFilteringEnabled != enabled;
     mFilteringEnabled = enabled;
 
-    if (needsRecompute && mCurrentTextureImage==NULL) {
+    if (needsRecompute && mCurrentTextureImage==nullptr) {
         GLC_LOGD("setFilteringEnabled called with mCurrentTextureImage == NULL");
     }
 
-    if (needsRecompute && mCurrentTextureImage != NULL) {
+    if (needsRecompute && mCurrentTextureImage != nullptr) {
         computeCurrentTransformMatrixLocked();
     }
 }
@@ -769,8 +741,7 @@
         GLC_LOGD("computeCurrentTransformMatrixLocked: "
                 "mCurrentTextureImage is NULL");
     }
-    computeTransformMatrix(mCurrentTransformMatrix, buf,
-        isEglImageCroppable(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop,
+    computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop,
         mCurrentTransform, mFilteringEnabled);
 }
 
@@ -938,7 +909,7 @@
     }
 
     return (mCurrentTextureImage == nullptr) ?
-            NULL : mCurrentTextureImage->graphicBuffer();
+            nullptr : mCurrentTextureImage->graphicBuffer();
 }
 
 Rect GLConsumer::getCurrentCrop() const {
@@ -1063,8 +1034,7 @@
 GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) :
     mGraphicBuffer(graphicBuffer),
     mEglImage(EGL_NO_IMAGE_KHR),
-    mEglDisplay(EGL_NO_DISPLAY),
-    mCropRect(Rect::EMPTY_RECT) {
+    mEglDisplay(EGL_NO_DISPLAY) {
 }
 
 GLConsumer::EglImage::~EglImage() {
@@ -1077,13 +1047,11 @@
 }
 
 status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
-                                              const Rect& cropRect,
                                               bool forceCreation) {
     // If there's an image and it's no longer valid, destroy it.
     bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
     bool displayInvalid = mEglDisplay != eglDisplay;
-    bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
-    if (haveImage && (displayInvalid || cropInvalid || forceCreation)) {
+    if (haveImage && (displayInvalid || forceCreation)) {
         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
            ALOGE("createIfNeeded: eglDestroyImageKHR failed");
         }
@@ -1095,14 +1063,12 @@
     // If there's no image, create one.
     if (mEglImage == EGL_NO_IMAGE_KHR) {
         mEglDisplay = eglDisplay;
-        mCropRect = cropRect;
-        mEglImage = createImage(mEglDisplay, mGraphicBuffer, mCropRect);
+        mEglImage = createImage(mEglDisplay, mGraphicBuffer);
     }
 
     // Fail if we can't create a valid image.
     if (mEglImage == EGL_NO_IMAGE_KHR) {
         mEglDisplay = EGL_NO_DISPLAY;
-        mCropRect.makeInvalid();
         const sp<GraphicBuffer>& buffer = mGraphicBuffer;
         ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
             buffer->getWidth(), buffer->getHeight(), buffer->getStride(),
@@ -1119,38 +1085,19 @@
 }
 
 EGLImageKHR GLConsumer::EglImage::createImage(EGLDisplay dpy,
-        const sp<GraphicBuffer>& graphicBuffer, const Rect& crop) {
+        const sp<GraphicBuffer>& graphicBuffer) {
     EGLClientBuffer cbuf =
             static_cast<EGLClientBuffer>(graphicBuffer->getNativeBuffer());
     const bool createProtectedImage =
             (graphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED) &&
             hasEglProtectedContent();
     EGLint attrs[] = {
-        EGL_IMAGE_PRESERVED_KHR,        EGL_TRUE,
-        EGL_IMAGE_CROP_LEFT_ANDROID,    crop.left,
-        EGL_IMAGE_CROP_TOP_ANDROID,     crop.top,
-        EGL_IMAGE_CROP_RIGHT_ANDROID,   crop.right,
-        EGL_IMAGE_CROP_BOTTOM_ANDROID,  crop.bottom,
+        EGL_IMAGE_PRESERVED_KHR, EGL_TRUE,
         createProtectedImage ? EGL_PROTECTED_CONTENT_EXT : EGL_NONE,
         createProtectedImage ? EGL_TRUE : EGL_NONE,
         EGL_NONE,
     };
-    if (!crop.isValid()) {
-        // No crop rect to set, so leave the crop out of the attrib array. Make
-        // sure to propagate the protected content attrs if they are set.
-        attrs[2] = attrs[10];
-        attrs[3] = attrs[11];
-        attrs[4] = EGL_NONE;
-    } else if (!isEglImageCroppable(crop)) {
-        // The crop rect is not at the origin, so we can't set the crop on the
-        // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
-        // extension.  In the future we can add a layered extension that
-        // removes this restriction if there is hardware that can support it.
-        attrs[2] = attrs[10];
-        attrs[3] = attrs[11];
-        attrs[4] = EGL_NONE;
-    }
-    eglInitialize(dpy, 0, 0);
+    eglInitialize(dpy, nullptr, nullptr);
     EGLImageKHR image = eglCreateImageKHR(dpy, EGL_NO_CONTEXT,
             EGL_NATIVE_BUFFER_ANDROID, cbuf, attrs);
     if (image == EGL_NO_IMAGE_KHR) {
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index 0b37960..68a6b1f 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -190,10 +190,10 @@
 
     virtual status_t detachNextBuffer(sp<GraphicBuffer>* outBuffer,
             sp<Fence>* outFence) {
-        if (outBuffer == NULL) {
+        if (outBuffer == nullptr) {
             ALOGE("detachNextBuffer: outBuffer must not be NULL");
             return BAD_VALUE;
-        } else if (outFence == NULL) {
+        } else if (outFence == nullptr) {
             ALOGE("detachNextBuffer: outFence must not be NULL");
             return BAD_VALUE;
         }
@@ -301,7 +301,7 @@
             int api, bool producerControlledByApp, QueueBufferOutput* output) {
         Parcel data, reply;
         data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
-        if (listener != NULL) {
+        if (listener != nullptr) {
             data.writeInt32(1);
             data.writeStrongBinder(IInterface::asBinder(listener));
         } else {
@@ -738,8 +738,8 @@
             int bufferIdx   = data.readInt32();
             sp<GraphicBuffer> buffer;
             int result = requestBuffer(bufferIdx, &buffer);
-            reply->writeInt32(buffer != 0);
-            if (buffer != 0) {
+            reply->writeInt32(buffer != nullptr);
+            if (buffer != nullptr) {
                 reply->write(*buffer);
             }
             reply->writeInt32(result);
@@ -797,12 +797,12 @@
             int32_t result = detachNextBuffer(&buffer, &fence);
             reply->writeInt32(result);
             if (result == NO_ERROR) {
-                reply->writeInt32(buffer != NULL);
-                if (buffer != NULL) {
+                reply->writeInt32(buffer != nullptr);
+                if (buffer != nullptr) {
                     reply->write(*buffer);
                 }
-                reply->writeInt32(fence != NULL);
-                if (fence != NULL) {
+                reply->writeInt32(fence != nullptr);
+                if (fence != nullptr) {
                     reply->write(*fence);
                 }
             }
diff --git a/libs/gui/StreamSplitter.cpp b/libs/gui/StreamSplitter.cpp
index 52c9067..2f8e104 100644
--- a/libs/gui/StreamSplitter.cpp
+++ b/libs/gui/StreamSplitter.cpp
@@ -38,11 +38,11 @@
 status_t StreamSplitter::createSplitter(
         const sp<IGraphicBufferConsumer>& inputQueue,
         sp<StreamSplitter>* outSplitter) {
-    if (inputQueue == NULL) {
+    if (inputQueue == nullptr) {
         ALOGE("createSplitter: inputQueue must not be NULL");
         return BAD_VALUE;
     }
-    if (outSplitter == NULL) {
+    if (outSplitter == nullptr) {
         ALOGE("createSplitter: outSplitter must not be NULL");
         return BAD_VALUE;
     }
@@ -74,7 +74,7 @@
 
 status_t StreamSplitter::addOutput(
         const sp<IGraphicBufferProducer>& outputQueue) {
-    if (outputQueue == NULL) {
+    if (outputQueue == nullptr) {
         ALOGE("addOutput: outputQueue must not be NULL");
         return BAD_VALUE;
     }
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 2de14c8..b505c6f 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -156,7 +156,7 @@
     ATRACE_CALL();
 
     DisplayStatInfo stats;
-    status_t result = composerService()->getDisplayStats(NULL, &stats);
+    status_t result = composerService()->getDisplayStats(nullptr, &stats);
     if (result != NO_ERROR) {
         return result;
     }
@@ -501,7 +501,7 @@
         if (mSharedBufferMode && mAutoRefresh && mSharedBufferSlot !=
                 BufferItem::INVALID_BUFFER_SLOT) {
             sp<GraphicBuffer>& gbuf(mSlots[mSharedBufferSlot].buffer);
-            if (gbuf != NULL) {
+            if (gbuf != nullptr) {
                 *buffer = gbuf.get();
                 *fenceFd = -1;
                 return OK;
@@ -541,7 +541,7 @@
     sp<GraphicBuffer>& gbuf(mSlots[buf].buffer);
 
     // this should never happen
-    ALOGE_IF(fence == NULL, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);
+    ALOGE_IF(fence == nullptr, "Surface::dequeueBuffer: received null Fence! buf=%d", buf);
 
     if (result & IGraphicBufferProducer::RELEASE_ALL_BUFFERS) {
         freeAllBuffers();
@@ -619,7 +619,7 @@
 int Surface::getSlotFromBufferLocked(
         android_native_buffer_t* buffer) const {
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        if (mSlots[i].buffer != NULL &&
+        if (mSlots[i].buffer != nullptr &&
                 mSlots[i].buffer->handle == buffer->handle) {
             return i;
         }
@@ -1268,7 +1268,7 @@
     ATRACE_CALL();
     ALOGV("Surface::detachNextBuffer");
 
-    if (outBuffer == NULL || outFence == NULL) {
+    if (outBuffer == nullptr || outFence == nullptr) {
         return BAD_VALUE;
     }
 
@@ -1277,8 +1277,8 @@
         mRemovedBuffers.clear();
     }
 
-    sp<GraphicBuffer> buffer(NULL);
-    sp<Fence> fence(NULL);
+    sp<GraphicBuffer> buffer(nullptr);
+    sp<Fence> fence(nullptr);
     status_t result = mGraphicBufferProducer->detachNextBuffer(
             &buffer, &fence);
     if (result != NO_ERROR) {
@@ -1286,19 +1286,19 @@
     }
 
     *outBuffer = buffer;
-    if (fence != NULL && fence->isValid()) {
+    if (fence != nullptr && fence->isValid()) {
         *outFence = fence;
     } else {
         *outFence = Fence::NO_FENCE;
     }
 
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        if (mSlots[i].buffer != NULL &&
+        if (mSlots[i].buffer != nullptr &&
                 mSlots[i].buffer->getId() == buffer->getId()) {
             if (mReportRemovedBuffers) {
                 mRemovedBuffers.push_back(mSlots[i].buffer);
             }
-            mSlots[i].buffer = NULL;
+            mSlots[i].buffer = nullptr;
         }
     }
 
@@ -1349,7 +1349,7 @@
     ATRACE_CALL();
 
     Rect realRect(Rect::EMPTY_RECT);
-    if (rect == NULL || rect->isEmpty()) {
+    if (rect == nullptr || rect->isEmpty()) {
         realRect.clear();
     } else {
         realRect = *rect;
@@ -1576,7 +1576,7 @@
 
 void Surface::freeAllBuffers() {
     for (int i = 0; i < NUM_BUFFER_SLOTS; i++) {
-        mSlots[i].buffer = 0;
+        mSlots[i].buffer = nullptr;
     }
 }
 
@@ -1616,12 +1616,12 @@
     // src and dst with, height and format must be identical. no verification
     // is done here.
     status_t err;
-    uint8_t* src_bits = NULL;
+    uint8_t* src_bits = nullptr;
     err = src->lock(GRALLOC_USAGE_SW_READ_OFTEN, reg.bounds(),
             reinterpret_cast<void**>(&src_bits));
     ALOGE_IF(err, "error locking src buffer %s", strerror(-err));
 
-    uint8_t* dst_bits = NULL;
+    uint8_t* dst_bits = nullptr;
     err = dst->lockAsync(GRALLOC_USAGE_SW_WRITE_OFTEN, reg.bounds(),
             reinterpret_cast<void**>(&dst_bits), *dstFenceFd);
     ALOGE_IF(err, "error locking dst buffer %s", strerror(-err));
@@ -1669,7 +1669,7 @@
 status_t Surface::lock(
         ANativeWindow_Buffer* outBuffer, ARect* inOutDirtyBounds)
 {
-    if (mLockedBuffer != 0) {
+    if (mLockedBuffer != nullptr) {
         ALOGE("Surface::lock failed, already locked");
         return INVALID_OPERATION;
     }
@@ -1701,7 +1701,7 @@
 
         // figure out if we can copy the frontbuffer back
         const sp<GraphicBuffer>& frontBuffer(mPostedBuffer);
-        const bool canCopyBack = (frontBuffer != 0 &&
+        const bool canCopyBack = (frontBuffer != nullptr &&
                 backBuffer->width  == frontBuffer->width &&
                 backBuffer->height == frontBuffer->height &&
                 backBuffer->format == frontBuffer->format);
@@ -1763,7 +1763,7 @@
 
 status_t Surface::unlockAndPost()
 {
-    if (mLockedBuffer == 0) {
+    if (mLockedBuffer == nullptr) {
         ALOGE("Surface::unlockAndPost failed, no locked buffer");
         return INVALID_OPERATION;
     }
@@ -1777,7 +1777,7 @@
             mLockedBuffer->handle, strerror(-err));
 
     mPostedBuffer = mLockedBuffer;
-    mLockedBuffer = 0;
+    mLockedBuffer = nullptr;
     return err;
 }
 
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 63560c4..fc076d2 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -60,7 +60,7 @@
     while (getService(name, &mComposerService) != NO_ERROR) {
         usleep(250000);
     }
-    assert(mComposerService != NULL);
+    assert(mComposerService != nullptr);
 
     // Create the death listener.
     class DeathObserver : public IBinder::DeathRecipient {
@@ -81,9 +81,9 @@
 /*static*/ sp<ISurfaceComposer> ComposerService::getComposerService() {
     ComposerService& instance = ComposerService::getInstance();
     Mutex::Autolock _l(instance.mLock);
-    if (instance.mComposerService == NULL) {
+    if (instance.mComposerService == nullptr) {
         ComposerService::getInstance().connectLocked();
-        assert(instance.mComposerService != NULL);
+        assert(instance.mComposerService != nullptr);
         ALOGD("ComposerService reconnected");
     }
     return instance.mComposerService;
@@ -92,8 +92,8 @@
 void ComposerService::composerServiceDied()
 {
     Mutex::Autolock _l(mLock);
-    mComposerService = NULL;
-    mDeathObserver = NULL;
+    mComposerService = nullptr;
+    mDeathObserver = nullptr;
 }
 
 // ---------------------------------------------------------------------------
@@ -571,12 +571,12 @@
 
 void SurfaceComposerClient::onFirstRef() {
     sp<ISurfaceComposer> sf(ComposerService::getComposerService());
-    if (sf != 0 && mStatus == NO_INIT) {
+    if (sf != nullptr && mStatus == NO_INIT) {
         auto rootProducer = mParent.promote();
         sp<ISurfaceComposerClient> conn;
         conn = (rootProducer != nullptr) ? sf->createScopedConnection(rootProducer) :
                 sf->createConnection();
-        if (conn != 0) {
+        if (conn != nullptr) {
             mClient = conn;
             mStatus = NO_ERROR;
         }
@@ -606,7 +606,7 @@
     // this can be called more than once.
     sp<ISurfaceComposerClient> client;
     Mutex::Autolock _lm(mLock);
-    if (mClient != 0) {
+    if (mClient != nullptr) {
         client = mClient; // hold ref while lock is held
         mClient.clear();
     }
@@ -766,7 +766,7 @@
                                    bool useIdentityTransform, uint32_t rotation,
                                    sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
-    if (s == NULL) return NO_INIT;
+    if (s == nullptr) return NO_INIT;
     status_t ret = s->captureScreen(display, outBuffer, sourceCrop, reqWidth, reqHeight, minLayerZ,
                                     maxLayerZ, useIdentityTransform,
                                     static_cast<ISurfaceComposer::Rotation>(rotation));
@@ -779,7 +779,7 @@
 status_t ScreenshotClient::captureLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
                                          float frameScale, sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
-    if (s == NULL) return NO_INIT;
+    if (s == nullptr) return NO_INIT;
     status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
                                     false /* childrenOnly */);
     return ret;
@@ -788,7 +788,7 @@
 status_t ScreenshotClient::captureChildLayers(const sp<IBinder>& layerHandle, Rect sourceCrop,
                                               float frameScale, sp<GraphicBuffer>* outBuffer) {
     sp<ISurfaceComposer> s(ComposerService::getComposerService());
-    if (s == NULL) return NO_INIT;
+    if (s == nullptr) return NO_INIT;
     status_t ret = s->captureLayers(layerHandle, outBuffer, sourceCrop, frameScale,
                                     true /* childrenOnly */);
     return ret;
diff --git a/libs/gui/SurfaceControl.cpp b/libs/gui/SurfaceControl.cpp
index 5eafbb3..19ad31b 100644
--- a/libs/gui/SurfaceControl.cpp
+++ b/libs/gui/SurfaceControl.cpp
@@ -86,7 +86,7 @@
 }
 
 void SurfaceControl::disconnect() {
-    if (mGraphicBufferProducer != NULL) {
+    if (mGraphicBufferProducer != nullptr) {
         mGraphicBufferProducer->disconnect(
                 BufferQueueCore::CURRENTLY_CONNECTED_API);
     }
@@ -95,7 +95,7 @@
 bool SurfaceControl::isSameSurface(
         const sp<SurfaceControl>& lhs, const sp<SurfaceControl>& rhs)
 {
-    if (lhs == 0 || rhs == 0)
+    if (lhs == nullptr || rhs == nullptr)
         return false;
     return lhs->mHandle == rhs->mHandle;
 }
@@ -116,7 +116,7 @@
 
 status_t SurfaceControl::validate() const
 {
-    if (mHandle==0 || mClient==0) {
+    if (mHandle==nullptr || mClient==nullptr) {
         ALOGE("invalid handle (%p) or client (%p)",
                 mHandle.get(), mClient.get());
         return NO_INIT;
@@ -128,7 +128,7 @@
         const sp<SurfaceControl>& control, Parcel* parcel)
 {
     sp<IGraphicBufferProducer> bp;
-    if (control != NULL) {
+    if (control != nullptr) {
         bp = control->mGraphicBufferProducer;
     }
     return parcel->writeStrongBinder(IInterface::asBinder(bp));
@@ -146,7 +146,7 @@
 sp<Surface> SurfaceControl::getSurface() const
 {
     Mutex::Autolock _l(mLock);
-    if (mSurfaceData == 0) {
+    if (mSurfaceData == nullptr) {
         return generateSurfaceLocked();
     }
     return mSurfaceData;
diff --git a/libs/gui/SyncFeatures.cpp b/libs/gui/SyncFeatures.cpp
index afa15c5..fcae05c 100644
--- a/libs/gui/SyncFeatures.cpp
+++ b/libs/gui/SyncFeatures.cpp
@@ -41,7 +41,7 @@
     // This can only be called after EGL has been initialized; otherwise the
     // check below will abort.
     const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
-    LOG_ALWAYS_FATAL_IF(exts == NULL, "eglQueryStringImplementationANDROID failed");
+    LOG_ALWAYS_FATAL_IF(exts == nullptr, "eglQueryStringImplementationANDROID failed");
     if (strstr(exts, "EGL_ANDROID_native_fence_sync")) {
         // This makes GLConsumer use the EGL_ANDROID_native_fence_sync
         // extension to create Android native fences to signal when all
diff --git a/libs/gui/include/gui/BufferHubProducer.h b/libs/gui/include/gui/BufferHubProducer.h
index 23c9909..f7af19b 100644
--- a/libs/gui/include/gui/BufferHubProducer.h
+++ b/libs/gui/include/gui/BufferHubProducer.h
@@ -165,6 +165,10 @@
     // buffers are acquired by the consumer, we can't .
     status_t FreeAllBuffers();
 
+    // Helper function that implements the detachBuffer() call, but assuming |mutex_| has been
+    // locked already.
+    status_t DetachBufferLocked(size_t slot);
+
     // Concreate implementation backed by BufferHubBuffer.
     std::shared_ptr<dvr::ProducerQueue> queue_;
 
diff --git a/libs/gui/include/gui/CpuConsumer.h b/libs/gui/include/gui/CpuConsumer.h
index d375611..806fbe8 100644
--- a/libs/gui/include/gui/CpuConsumer.h
+++ b/libs/gui/include/gui/CpuConsumer.h
@@ -70,7 +70,7 @@
         uint32_t    chromaStep;
 
         LockedBuffer() :
-            data(NULL),
+            data(nullptr),
             width(0),
             height(0),
             format(PIXEL_FORMAT_NONE),
@@ -82,8 +82,8 @@
             dataSpace(HAL_DATASPACE_UNKNOWN),
             frameNumber(0),
             flexFormat(PIXEL_FORMAT_NONE),
-            dataCb(NULL),
-            dataCr(NULL),
+            dataCb(nullptr),
+            dataCr(nullptr),
             chromaStride(0),
             chromaStep(0)
         {}
diff --git a/libs/gui/include/gui/GLConsumer.h b/libs/gui/include/gui/GLConsumer.h
index 71ed3bf..46a99e1 100644
--- a/libs/gui/include/gui/GLConsumer.h
+++ b/libs/gui/include/gui/GLConsumer.h
@@ -140,7 +140,8 @@
 
     // Scale the crop down horizontally or vertically such that it has the
     // same aspect ratio as the buffer does.
-    static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth, uint32_t bufferHeight);
+    static Rect scaleDownCrop(const Rect& crop, uint32_t bufferWidth,
+            uint32_t bufferHeight);
 
     // getTimestamp retrieves the timestamp associated with the texture image
     // set by the most recent call to updateTexImage.
@@ -305,7 +306,6 @@
         // createIfNeeded creates an EGLImage if required (we haven't created
         // one yet, or the EGLDisplay or crop-rect has changed).
         status_t createIfNeeded(EGLDisplay display,
-                                const Rect& cropRect,
                                 bool forceCreate = false);
 
         // This calls glEGLImageTargetTexture2DOES to bind the image to the
@@ -314,7 +314,7 @@
 
         const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
         const native_handle* graphicBufferHandle() {
-            return mGraphicBuffer == NULL ? NULL : mGraphicBuffer->handle;
+            return mGraphicBuffer == nullptr ? nullptr : mGraphicBuffer->handle;
         }
 
     private:
@@ -324,7 +324,7 @@
 
         // createImage creates a new EGLImage from a GraphicBuffer.
         EGLImageKHR createImage(EGLDisplay dpy,
-                const sp<GraphicBuffer>& graphicBuffer, const Rect& crop);
+                const sp<GraphicBuffer>& graphicBuffer);
 
         // Disallow copying
         EglImage(const EglImage& rhs);
diff --git a/libs/gui/include/gui/IGraphicBufferProducer.h b/libs/gui/include/gui/IGraphicBufferProducer.h
index 887654e..8ff8d81 100644
--- a/libs/gui/include/gui/IGraphicBufferProducer.h
+++ b/libs/gui/include/gui/IGraphicBufferProducer.h
@@ -345,7 +345,7 @@
             *outScalingMode = scalingMode;
             *outTransform = transform;
             *outFence = fence;
-            if (outStickyTransform != NULL) {
+            if (outStickyTransform != nullptr) {
                 *outStickyTransform = stickyTransform;
             }
             if (outGetFrameTimestamps) {
diff --git a/libs/gui/include/gui/Surface.h b/libs/gui/include/gui/Surface.h
index 9aeafae..32ee595 100644
--- a/libs/gui/include/gui/Surface.h
+++ b/libs/gui/include/gui/Surface.h
@@ -80,7 +80,7 @@
     /* convenience function to check that the given surface is non NULL as
      * well as its IGraphicBufferProducer */
     static bool isValid(const sp<Surface>& surface) {
-        return surface != NULL && surface->getIGraphicBufferProducer() != NULL;
+        return surface != nullptr && surface->getIGraphicBufferProducer() != nullptr;
     }
 
     /* Attaches a sideband buffer stream to the Surface's IGraphicBufferProducer.
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 377fe68..34708c7 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -69,7 +69,7 @@
 
     // callback when the composer is dies
     status_t linkToComposerDeath(const sp<IBinder::DeathRecipient>& recipient,
-            void* cookie = NULL, uint32_t flags = 0);
+            void* cookie = nullptr, uint32_t flags = 0);
 
     // Get a list of supported configurations for a given display
     static status_t getDisplayConfigs(const sp<IBinder>& display,
diff --git a/libs/gui/include/gui/SurfaceControl.h b/libs/gui/include/gui/SurfaceControl.h
index bd987dd..ccb30fa 100644
--- a/libs/gui/include/gui/SurfaceControl.h
+++ b/libs/gui/include/gui/SurfaceControl.h
@@ -48,11 +48,11 @@
     void writeToParcel(Parcel* parcel);
 
     static bool isValid(const sp<SurfaceControl>& surface) {
-        return (surface != 0) && surface->isValid();
+        return (surface != nullptr) && surface->isValid();
     }
 
     bool isValid() {
-        return mHandle!=0 && mClient!=0;
+        return mHandle!=nullptr && mClient!=nullptr;
     }
 
     static bool isSameSurface(
diff --git a/libs/gui/tests/Android.bp b/libs/gui/tests/Android.bp
index 01e90e0..02064c6 100644
--- a/libs/gui/tests/Android.bp
+++ b/libs/gui/tests/Android.bp
@@ -50,9 +50,12 @@
     ],
 }
 
-// Build a separate binary for each source file to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+// Build a separate binary to $(TARGET_OUT_DATA_NATIVE_TESTS)/$(LOCAL_MODULE)
+// This test has a main method, and requires a separate binary to be built.
+// To add move tests like this, just add additional cc_test statements,
+// as opposed to adding more source files to this one.
 cc_test {
-    name: "libgui_separate_binary_test",
+    name: "SurfaceParcelable_test",
     test_suites: ["device-tests"],
 
     clang: true,
@@ -61,7 +64,6 @@
         "-Werror",
     ],
 
-    test_per_src: true,
     srcs: [
         "SurfaceParcelable_test.cpp",
     ],
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index 9a20859..119e888 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -61,7 +61,7 @@
     }
 
     void GetMinUndequeuedBufferCount(int* bufferCount) {
-        ASSERT_TRUE(bufferCount != NULL);
+        ASSERT_TRUE(bufferCount != nullptr);
         ASSERT_EQ(OK, mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
                     bufferCount));
         ASSERT_GE(*bufferCount, 0);
@@ -82,7 +82,7 @@
         sp<Fence> fence;
 
         input.deflate(&timestamp, &isAutoTimestamp, &dataSpace, &crop,
-                &scalingMode, &transform, &fence, NULL);
+                &scalingMode, &transform, &fence, nullptr);
         ASSERT_EQ(timestamp, item.mTimestamp);
         ASSERT_EQ(isAutoTimestamp, item.mIsAutoTimestamp);
         ASSERT_EQ(dataSpace, item.mDataSpace);
@@ -128,17 +128,17 @@
     sp<IBinder> binderProducer =
         serviceManager->getService(PRODUCER_NAME);
     mProducer = interface_cast<IGraphicBufferProducer>(binderProducer);
-    EXPECT_TRUE(mProducer != NULL);
+    EXPECT_TRUE(mProducer != nullptr);
     sp<IBinder> binderConsumer =
         serviceManager->getService(CONSUMER_NAME);
     mConsumer = interface_cast<IGraphicBufferConsumer>(binderConsumer);
-    EXPECT_TRUE(mConsumer != NULL);
+    EXPECT_TRUE(mConsumer != nullptr);
 
     sp<DummyConsumer> dc(new DummyConsumer);
     ASSERT_EQ(OK, mConsumer->consumerConnect(dc, false));
     IGraphicBufferProducer::QueueBufferOutput output;
     ASSERT_EQ(OK,
-            mProducer->connect(NULL, NATIVE_WINDOW_API_CPU, false, &output));
+            mProducer->connect(nullptr, NATIVE_WINDOW_API_CPU, false, &output));
 
     int slot;
     sp<Fence> fence;
@@ -353,8 +353,8 @@
     ASSERT_EQ(OK, buffer->unlock());
 
     int newSlot;
-    ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(NULL, safeToClobberBuffer));
-    ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&newSlot, NULL));
+    ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(nullptr, safeToClobberBuffer));
+    ASSERT_EQ(BAD_VALUE, mProducer->attachBuffer(&newSlot, nullptr));
 
     ASSERT_EQ(OK, mProducer->attachBuffer(&newSlot, buffer));
     IGraphicBufferProducer::QueueBufferInput input(0, false,
@@ -412,8 +412,8 @@
 
     int newSlot;
     sp<GraphicBuffer> safeToClobberBuffer;
-    ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(NULL, safeToClobberBuffer));
-    ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(&newSlot, NULL));
+    ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(nullptr, safeToClobberBuffer));
+    ASSERT_EQ(BAD_VALUE, mConsumer->attachBuffer(&newSlot, nullptr));
     ASSERT_EQ(OK, mConsumer->attachBuffer(&newSlot, item.mGraphicBuffer));
 
     ASSERT_EQ(OK, mConsumer->releaseBuffer(newSlot, 0, EGL_NO_DISPLAY,
diff --git a/libs/gui/tests/CpuConsumer_test.cpp b/libs/gui/tests/CpuConsumer_test.cpp
index 36be7d9..00e32d9 100644
--- a/libs/gui/tests/CpuConsumer_test.cpp
+++ b/libs/gui/tests/CpuConsumer_test.cpp
@@ -484,12 +484,12 @@
     err = native_window_dequeue_buffer_and_wait(anw.get(), &anb);
     ASSERT_NO_ERROR(err, "dequeueBuffer error: ");
 
-    ASSERT_TRUE(anb != NULL);
+    ASSERT_TRUE(anb != nullptr);
 
     sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     *stride = buf->getStride();
-    uint8_t* img = NULL;
+    uint8_t* img = nullptr;
 
     ALOGVV("Lock buffer from %p for write", anw.get());
     err = buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
@@ -554,7 +554,7 @@
     err = mCC->lockNextBuffer(&b);
     ASSERT_NO_ERROR(err, "getNextBuffer error: ");
 
-    ASSERT_TRUE(b.data != NULL);
+    ASSERT_TRUE(b.data != nullptr);
     EXPECT_EQ(params.width,  b.width);
     EXPECT_EQ(params.height, b.height);
     EXPECT_EQ(params.format, b.format);
@@ -595,7 +595,7 @@
         err = mCC->lockNextBuffer(&b);
         ASSERT_NO_ERROR(err, "getNextBuffer error: ");
 
-        ASSERT_TRUE(b.data != NULL);
+        ASSERT_TRUE(b.data != nullptr);
         EXPECT_EQ(params.width,  b.width);
         EXPECT_EQ(params.height, b.height);
         EXPECT_EQ(params.format, b.format);
@@ -637,7 +637,7 @@
         err = mCC->lockNextBuffer(&b[i]);
         ASSERT_NO_ERROR(err, "getNextBuffer error: ");
 
-        ASSERT_TRUE(b[i].data != NULL);
+        ASSERT_TRUE(b[i].data != nullptr);
         EXPECT_EQ(params.width,  b[i].width);
         EXPECT_EQ(params.height, b[i].height);
         EXPECT_EQ(params.format, b[i].format);
@@ -660,7 +660,7 @@
     err = mCC->lockNextBuffer(&bTooMuch);
     ASSERT_NO_ERROR(err, "Did not allow new lock after unlock");
 
-    ASSERT_TRUE(bTooMuch.data != NULL);
+    ASSERT_TRUE(bTooMuch.data != nullptr);
     EXPECT_EQ(params.width,  bTooMuch.width);
     EXPECT_EQ(params.height, bTooMuch.height);
     EXPECT_EQ(params.format, bTooMuch.format);
diff --git a/libs/gui/tests/FillBuffer.cpp b/libs/gui/tests/FillBuffer.cpp
index ccd674f..b60995a 100644
--- a/libs/gui/tests/FillBuffer.cpp
+++ b/libs/gui/tests/FillBuffer.cpp
@@ -93,11 +93,11 @@
     android_native_buffer_t* anb;
     ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(anw.get(),
             &anb));
-    ASSERT_TRUE(anb != NULL);
+    ASSERT_TRUE(anb != nullptr);
 
     sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
-    uint8_t* img = NULL;
+    uint8_t* img = nullptr;
     ASSERT_EQ(NO_ERROR, buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN,
             (void**)(&img)));
     fillRGBA8Buffer(img, buf->getWidth(), buf->getHeight(), buf->getStride());
diff --git a/libs/gui/tests/GLTest.cpp b/libs/gui/tests/GLTest.cpp
index a91552f..a1405fc 100644
--- a/libs/gui/tests/GLTest.cpp
+++ b/libs/gui/tests/GLTest.cpp
@@ -50,7 +50,7 @@
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
 
     char* displaySecsEnv = getenv("GLTEST_DISPLAY_SECS");
-    if (displaySecsEnv != NULL) {
+    if (displaySecsEnv != nullptr) {
         mDisplaySecs = atoi(displaySecsEnv);
         if (mDisplaySecs < 0) {
             mDisplaySecs = 0;
@@ -67,7 +67,7 @@
                 String8("Test Surface"), getSurfaceWidth(), getSurfaceHeight(),
                 PIXEL_FORMAT_RGB_888, 0);
 
-        ASSERT_TRUE(mSurfaceControl != NULL);
+        ASSERT_TRUE(mSurfaceControl != nullptr);
         ASSERT_TRUE(mSurfaceControl->isValid());
 
         Transaction t;
@@ -117,7 +117,7 @@
         sleep(mDisplaySecs);
     }
 
-    if (mComposerClient != NULL) {
+    if (mComposerClient != nullptr) {
         mComposerClient->dispose();
     }
     if (mEglContext != EGL_NO_CONTEXT) {
@@ -171,7 +171,7 @@
 
 EGLSurface GLTest::createWindowSurface(EGLDisplay display, EGLConfig config,
                                        sp<ANativeWindow>& window) const {
-    return eglCreateWindowSurface(display, config, window.get(), NULL);
+    return eglCreateWindowSurface(display, config, window.get(), nullptr);
 }
 
 ::testing::AssertionResult GLTest::checkPixel(int x, int y,
@@ -256,7 +256,7 @@
     GLuint shader = glCreateShader(shaderType);
     ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
     if (shader) {
-        glShaderSource(shader, 1, &pSource, NULL);
+        glShaderSource(shader, 1, &pSource, nullptr);
         ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
         glCompileShader(shader);
         ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
@@ -270,7 +270,7 @@
             if (infoLen) {
                 char* buf = (char*) malloc(infoLen);
                 if (buf) {
-                    glGetShaderInfoLog(shader, infoLen, NULL, buf);
+                    glGetShaderInfoLog(shader, infoLen, nullptr, buf);
                     printf("Shader compile log:\n%s\n", buf);
                     free(buf);
                     FAIL();
@@ -278,7 +278,7 @@
             } else {
                 char* buf = (char*) malloc(0x1000);
                 if (buf) {
-                    glGetShaderInfoLog(shader, 0x1000, NULL, buf);
+                    glGetShaderInfoLog(shader, 0x1000, nullptr, buf);
                     printf("Shader compile log:\n%s\n", buf);
                     free(buf);
                     FAIL();
@@ -322,7 +322,7 @@
             if (bufLength) {
                 char* buf = (char*) malloc(bufLength);
                 if (buf) {
-                    glGetProgramInfoLog(program, bufLength, NULL, buf);
+                    glGetProgramInfoLog(program, bufLength, nullptr, buf);
                     printf("Program link log:\n%s\n", buf);
                     free(buf);
                     FAIL();
diff --git a/libs/gui/tests/GLTest.h b/libs/gui/tests/GLTest.h
index f0d27a8..f290b3c 100644
--- a/libs/gui/tests/GLTest.h
+++ b/libs/gui/tests/GLTest.h
@@ -39,7 +39,7 @@
             mEglDisplay(EGL_NO_DISPLAY),
             mEglSurface(EGL_NO_SURFACE),
             mEglContext(EGL_NO_CONTEXT),
-            mGlConfig(NULL) {
+            mGlConfig(nullptr) {
     }
 
     virtual void SetUp();
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index a35cf11..6d03374 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -228,9 +228,9 @@
     void setupDequeueRequestBuffer(int *slot, sp<Fence> *fence,
             sp<GraphicBuffer> *buffer)
     {
-        ASSERT_TRUE(slot != NULL);
-        ASSERT_TRUE(fence != NULL);
-        ASSERT_TRUE(buffer != NULL);
+        ASSERT_TRUE(slot != nullptr);
+        ASSERT_TRUE(fence != nullptr);
+        ASSERT_TRUE(buffer != nullptr);
 
         ASSERT_NO_FATAL_FAILURE(ConnectProducer());
 
@@ -263,7 +263,7 @@
     EXPECT_EQ(BAD_VALUE, mProducer->connect(TEST_TOKEN,
                                             TEST_API,
                                             TEST_CONTROLLED_BY_APP,
-                                            /*output*/NULL));
+                                            /*output*/nullptr));
 
     // Invalid API returns bad value
     EXPECT_EQ(BAD_VALUE, mProducer->connect(TEST_TOKEN,
@@ -359,7 +359,7 @@
     // TODO: Consider documented the above enums as unsupported or make a new enum for IGBP
 
     // Value was NULL
-    EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_FORMAT, /*value*/NULL));
+    EXPECT_EQ(BAD_VALUE, mProducer->query(NATIVE_WINDOW_FORMAT, /*value*/nullptr));
 
     ASSERT_OK(mConsumer->consumerDisconnect());
 
@@ -465,7 +465,7 @@
 
     // Fence was NULL
     {
-        sp<Fence> nullFence = NULL;
+        sp<Fence> nullFence = nullptr;
 
         IGraphicBufferProducer::QueueBufferInput input =
                 QueueBufferInputBuilder().setFence(nullFence).build();
@@ -695,10 +695,7 @@
     sp<Fence> fence;
     sp<GraphicBuffer> buffer;
 
-    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
-        // TODO(b/38137191): Implement BufferHubProducer::detachBuffer
-        ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence));
-    }
+    ASSERT_EQ(NO_INIT, mProducer->detachNextBuffer(&buffer, &fence));
 }
 
 TEST_P(IGraphicBufferProducerTest,
@@ -735,10 +732,7 @@
 
     ASSERT_OK(mProducer->disconnect(TEST_API));
 
-    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
-        // TODO(b/38137191): Implement BufferHubProducer::detachBuffer
-        ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot));
-    }
+    ASSERT_EQ(NO_INIT, mProducer->detachBuffer(slot));
 }
 
 TEST_P(IGraphicBufferProducerTest,
@@ -778,18 +772,46 @@
     sp<GraphicBuffer> buffer;
 
     setupDequeueRequestBuffer(&slot, &fence, &buffer);
+    ASSERT_TRUE(buffer != nullptr);
 
-    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
-        // TODO(b/38137191): Implement BufferHubProducer::detachBuffer
-        ASSERT_OK(mProducer->detachBuffer(slot));
+    ASSERT_OK(mProducer->detachBuffer(slot));
+    EXPECT_OK(buffer->initCheck());
+
+    if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
+        // For a GraphicBuffer backed by BufferHub, once detached from an IGBP, it should have
+        // isDetachedBuffer() set. Note that this only applies to BufferHub.
+        EXPECT_TRUE(buffer->isDetachedBuffer());
+    } else {
+        EXPECT_FALSE(buffer->isDetachedBuffer());
     }
 
     ASSERT_OK(mProducer->disconnect(TEST_API));
 
-    if (GetParam() == USE_BUFFER_QUEUE_PRODUCER) {
-        // TODO(b/69981968): Implement BufferHubProducer::attachBuffer
-        ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
+    ASSERT_EQ(NO_INIT, mProducer->attachBuffer(&slot, buffer));
+}
+
+TEST_P(IGraphicBufferProducerTest, DetachThenAttach_Succeeds) {
+    int slot = -1;
+    sp<Fence> fence;
+    sp<GraphicBuffer> buffer;
+
+    setupDequeueRequestBuffer(&slot, &fence, &buffer);
+    ASSERT_TRUE(buffer != nullptr);
+
+    ASSERT_OK(mProducer->detachBuffer(slot));
+    EXPECT_OK(buffer->initCheck());
+
+    if (GetParam() == USE_BUFFER_HUB_PRODUCER) {
+        // For a GraphicBuffer backed by BufferHub, once detached from an IGBP, it should have
+        // isDetachedBuffer() set. Note that this only applies to BufferHub.
+        EXPECT_TRUE(buffer->isDetachedBuffer());
+    } else {
+        EXPECT_FALSE(buffer->isDetachedBuffer());
     }
+
+    EXPECT_OK(mProducer->attachBuffer(&slot, buffer));
+    EXPECT_FALSE(buffer->isDetachedBuffer());
+    EXPECT_OK(buffer->initCheck());
 }
 
 #if USE_BUFFER_HUB_AS_BUFFER_QUEUE
diff --git a/libs/gui/tests/MultiTextureConsumer_test.cpp b/libs/gui/tests/MultiTextureConsumer_test.cpp
index 3a25ac5..7d3d4aa 100644
--- a/libs/gui/tests/MultiTextureConsumer_test.cpp
+++ b/libs/gui/tests/MultiTextureConsumer_test.cpp
@@ -47,7 +47,7 @@
         GLTest::TearDown();
     }
     virtual EGLint const* getContextAttribs() {
-        return NULL;
+        return nullptr;
     }
     virtual EGLint const* getConfigAttribs() {
         static EGLint sDefaultConfigAttribs[] = {
@@ -105,7 +105,7 @@
 
     glClear(GL_COLOR_BUFFER_BIT);
     for (int i=0 ; i<8 ; i++) {
-        mSurface->lock(&buffer, NULL);
+        mSurface->lock(&buffer, nullptr);
         memset(buffer.bits, (i&7) * 0x20, buffer.stride * buffer.height * 4);
         mSurface->unlockAndPost();
 
diff --git a/libs/gui/tests/SurfaceTextureClient_test.cpp b/libs/gui/tests/SurfaceTextureClient_test.cpp
index d5b2f00..65e09f2 100644
--- a/libs/gui/tests/SurfaceTextureClient_test.cpp
+++ b/libs/gui/tests/SurfaceTextureClient_test.cpp
@@ -29,7 +29,6 @@
 #include <utils/Thread.h>
 
 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
-#define CROP_EXT_STR "EGL_ANDROID_image_crop"
 
 namespace android {
 
@@ -39,7 +38,7 @@
             mEglDisplay(EGL_NO_DISPLAY),
             mEglSurface(EGL_NO_SURFACE),
             mEglContext(EGL_NO_CONTEXT),
-            mEglConfig(NULL) {
+            mEglConfig(nullptr) {
     }
 
     virtual void SetUp() {
@@ -82,7 +81,7 @@
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
         ASSERT_NE(EGL_NO_SURFACE, mEglSurface);
 
-        mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT, 0);
+        mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT, nullptr);
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
         ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
 
@@ -127,7 +126,7 @@
 
 TEST_F(SurfaceTextureClientTest, GetISurfaceTextureIsNotNull) {
     sp<IGraphicBufferProducer> ist(mSTC->getIGraphicBufferProducer());
-    ASSERT_TRUE(ist != NULL);
+    ASSERT_TRUE(ist != nullptr);
 }
 
 TEST_F(SurfaceTextureClientTest, QueuesToWindowCompositorIsFalse) {
@@ -155,7 +154,7 @@
     EXPECT_TRUE(eglInitialize(dpy, &majorVersion, &minorVersion));
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
 
-    EGLConfig myConfig = {0};
+    EGLConfig myConfig = {nullptr};
     EGLint numConfigs = 0;
     EGLint configAttribs[] = {
         EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
@@ -172,7 +171,7 @@
     ASSERT_EQ(EGL_SUCCESS, eglGetError());
 
     EGLSurface eglSurface = eglCreateWindowSurface(dpy, myConfig, mANW.get(),
-            NULL);
+            nullptr);
     EXPECT_NE(EGL_NO_SURFACE, eglSurface);
     EXPECT_EQ(EGL_SUCCESS, eglGetError());
 
@@ -185,7 +184,7 @@
 
 TEST_F(SurfaceTextureClientTest, EglSwapBuffersAbandonErrorIsEglBadSurface) {
 
-    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, mANW.get(), NULL);
+    EGLSurface eglSurface = eglCreateWindowSurface(mEglDisplay, mEglConfig, mANW.get(), nullptr);
     EXPECT_NE(EGL_NO_SURFACE, eglSurface);
     EXPECT_EQ(EGL_SUCCESS, eglGetError());
 
@@ -638,18 +637,6 @@
 }
 
 TEST_F(SurfaceTextureClientTest, GetTransformMatrixSucceedsAfterFreeingBuffersWithCrop) {
-    // Query to see if the image crop extension exists
-    EGLDisplay dpy = eglGetDisplay(EGL_DEFAULT_DISPLAY);
-    const char* exts = eglQueryStringImplementationANDROID(dpy, EGL_EXTENSIONS);
-    size_t cropExtLen = strlen(CROP_EXT_STR);
-    size_t extsLen = strlen(exts);
-    bool equal = !strcmp(CROP_EXT_STR, exts);
-    bool atStart = !strncmp(CROP_EXT_STR " ", exts, cropExtLen+1);
-    bool atEnd = (cropExtLen+1) < extsLen &&
-            !strcmp(" " CROP_EXT_STR, exts + extsLen - (cropExtLen+1));
-    bool inMiddle = strstr(exts, " " CROP_EXT_STR " ");
-    bool hasEglAndroidImageCrop = equal || atStart || atEnd || inMiddle;
-
     android_native_buffer_t* buf[3];
     float mtx[16] = {};
     android_native_rect_t crop;
@@ -669,17 +656,15 @@
     ASSERT_EQ(OK, native_window_set_buffer_count(mANW.get(), 6)); // frees buffers
     mST->getTransformMatrix(mtx);
 
-    // If the egl image crop extension is not present, this accounts for the
-    // .5 texel shrink for each edge that's included in the transform matrix
-    // to avoid texturing outside the crop region. Otherwise the crop is not
-    // included in the transform matrix.
-    EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5, mtx[0]);
+    // This accounts for the .5 texel shrink for each edge that's included in
+    // the transform matrix to avoid texturing outside the crop region.
+    EXPECT_EQ(0.5f, mtx[0]);
     EXPECT_EQ(0.f, mtx[1]);
     EXPECT_EQ(0.f, mtx[2]);
     EXPECT_EQ(0.f, mtx[3]);
 
     EXPECT_EQ(0.f, mtx[4]);
-    EXPECT_EQ(hasEglAndroidImageCrop ? -1 : -0.5, mtx[5]);
+    EXPECT_EQ(-0.5f, mtx[5]);
     EXPECT_EQ(0.f, mtx[6]);
     EXPECT_EQ(0.f, mtx[7]);
 
@@ -688,8 +673,8 @@
     EXPECT_EQ(1.f, mtx[10]);
     EXPECT_EQ(0.f, mtx[11]);
 
-    EXPECT_EQ(hasEglAndroidImageCrop ? 0 : 0.0625f, mtx[12]);
-    EXPECT_EQ(hasEglAndroidImageCrop ? 1 : 0.5625f, mtx[13]);
+    EXPECT_EQ(0.0625f, mtx[12]);
+    EXPECT_EQ(0.5625f, mtx[13]);
     EXPECT_EQ(0.f, mtx[14]);
     EXPECT_EQ(1.f, mtx[15]);
 }
@@ -753,7 +738,7 @@
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
 
         mEglContext = eglCreateContext(mEglDisplay, myConfig, EGL_NO_CONTEXT,
-                0);
+                nullptr);
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
         ASSERT_NE(EGL_NO_CONTEXT, mEglContext);
 
@@ -765,7 +750,7 @@
                     GLConsumer::TEXTURE_EXTERNAL, true, false));
             sp<Surface> stc(new Surface(producer));
             mEglSurfaces[i] = eglCreateWindowSurface(mEglDisplay, myConfig,
-                    static_cast<ANativeWindow*>(stc.get()), NULL);
+                    static_cast<ANativeWindow*>(stc.get()), nullptr);
             ASSERT_EQ(EGL_SUCCESS, eglGetError());
             ASSERT_NE(EGL_NO_SURFACE, mEglSurfaces[i]);
         }
diff --git a/libs/gui/tests/SurfaceTextureFBO.h b/libs/gui/tests/SurfaceTextureFBO.h
index 7f1ae84..70f988d 100644
--- a/libs/gui/tests/SurfaceTextureFBO.h
+++ b/libs/gui/tests/SurfaceTextureFBO.h
@@ -34,7 +34,7 @@
         glGenTextures(1, &mFboTex);
         glBindTexture(GL_TEXTURE_2D, mFboTex);
         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, getSurfaceWidth(),
-                getSurfaceHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+                getSurfaceHeight(), 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr);
         glBindTexture(GL_TEXTURE_2D, 0);
         ASSERT_EQ(GLenum(GL_NO_ERROR), glGetError());
 
diff --git a/libs/gui/tests/SurfaceTextureFBO_test.cpp b/libs/gui/tests/SurfaceTextureFBO_test.cpp
index 0134273..f34561f 100644
--- a/libs/gui/tests/SurfaceTextureFBO_test.cpp
+++ b/libs/gui/tests/SurfaceTextureFBO_test.cpp
@@ -39,12 +39,12 @@
     android_native_buffer_t* anb;
     ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
             &anb));
-    ASSERT_TRUE(anb != NULL);
+    ASSERT_TRUE(anb != nullptr);
 
     sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     // Fill the buffer with green
-    uint8_t* img = NULL;
+    uint8_t* img = nullptr;
     buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
     fillRGBA8BufferSolid(img, texWidth, texHeight, buf->getStride(), 0, 255,
             0, 255);
@@ -63,7 +63,7 @@
 
         ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
                 &anb));
-        ASSERT_TRUE(anb != NULL);
+        ASSERT_TRUE(anb != nullptr);
 
         buf = GraphicBuffer::from(anb);
 
diff --git a/libs/gui/tests/SurfaceTextureGLThreadToGL.h b/libs/gui/tests/SurfaceTextureGLThreadToGL.h
index 2ce20eb..03975b1 100644
--- a/libs/gui/tests/SurfaceTextureGLThreadToGL.h
+++ b/libs/gui/tests/SurfaceTextureGLThreadToGL.h
@@ -158,7 +158,7 @@
     }
 
     virtual void TearDown() {
-        if (mProducerThread != NULL) {
+        if (mProducerThread != nullptr) {
             mProducerThread->requestExitAndWait();
         }
         mProducerThread.clear();
@@ -167,7 +167,7 @@
     }
 
     void runProducerThread(const sp<ProducerThread> producerThread) {
-        ASSERT_TRUE(mProducerThread == NULL);
+        ASSERT_TRUE(mProducerThread == nullptr);
         mProducerThread = producerThread;
         producerThread->setEglObjects(mEglDisplay, mProducerEglSurface,
                 mProducerEglContext);
diff --git a/libs/gui/tests/SurfaceTextureGLToGL.h b/libs/gui/tests/SurfaceTextureGLToGL.h
index 5d43a48..3a87c12 100644
--- a/libs/gui/tests/SurfaceTextureGLToGL.h
+++ b/libs/gui/tests/SurfaceTextureGLToGL.h
@@ -38,7 +38,7 @@
 
     void SetUpWindowAndContext() {
         mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
-                mANW.get(), NULL);
+                mANW.get(), nullptr);
         ASSERT_EQ(EGL_SUCCESS, eglGetError());
         ASSERT_NE(EGL_NO_SURFACE, mProducerEglSurface);
 
diff --git a/libs/gui/tests/SurfaceTextureGL_test.cpp b/libs/gui/tests/SurfaceTextureGL_test.cpp
index 5639286..e2b4f3d 100644
--- a/libs/gui/tests/SurfaceTextureGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGL_test.cpp
@@ -40,12 +40,12 @@
     ANativeWindowBuffer* anb;
     ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
             &anb));
-    ASSERT_TRUE(anb != NULL);
+    ASSERT_TRUE(anb != nullptr);
 
     sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     // Fill the buffer with the a checkerboard pattern
-    uint8_t* img = NULL;
+    uint8_t* img = nullptr;
     buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
     fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
     buf->unlock();
@@ -90,12 +90,12 @@
     ANativeWindowBuffer* anb;
     ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
             &anb));
-    ASSERT_TRUE(anb != NULL);
+    ASSERT_TRUE(anb != nullptr);
 
     sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
     // Fill the buffer with the a checkerboard pattern
-    uint8_t* img = NULL;
+    uint8_t* img = nullptr;
     buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
     fillYV12Buffer(img, texWidth, texHeight, buf->getStride());
     buf->unlock();
@@ -155,11 +155,11 @@
         ANativeWindowBuffer* anb;
         ASSERT_EQ(NO_ERROR, native_window_dequeue_buffer_and_wait(mANW.get(),
                 &anb));
-        ASSERT_TRUE(anb != NULL);
+        ASSERT_TRUE(anb != nullptr);
 
         sp<GraphicBuffer> buf(GraphicBuffer::from(anb));
 
-        uint8_t* img = NULL;
+        uint8_t* img = nullptr;
         buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
         fillYV12BufferRect(img, texWidth, texHeight, buf->getStride(), crop);
         buf->unlock();
@@ -234,7 +234,7 @@
                         &anb) != NO_ERROR) {
                     return false;
                 }
-                if (anb == NULL) {
+                if (anb == nullptr) {
                     return false;
                 }
 
@@ -248,7 +248,7 @@
                 int yuvTexOffsetU = yuvTexOffsetV + yuvTexStrideV * texHeight/2;
                 int yuvTexStrideU = yuvTexStrideV;
 
-                uint8_t* img = NULL;
+                uint8_t* img = nullptr;
                 buf->lock(GRALLOC_USAGE_SW_WRITE_OFTEN, (void**)(&img));
 
                 // Gray out all the test pixels first, so we're more likely to
@@ -457,7 +457,7 @@
                         &anb) != NO_ERROR) {
                     return false;
                 }
-                if (anb == NULL) {
+                if (anb == nullptr) {
                     return false;
                 }
                 if (mANW->queueBuffer(mANW.get(), anb, -1)
@@ -641,7 +641,7 @@
                     &anb) != NO_ERROR) {
                 return false;
             }
-            if (anb == NULL) {
+            if (anb == nullptr) {
                 return false;
             }
             if (mANW->queueBuffer(mANW.get(), anb, -1)
@@ -654,7 +654,7 @@
                     &anb) != NO_ERROR) {
                 return false;
             }
-            if (anb == NULL) {
+            if (anb == nullptr) {
                 return false;
             }
             if (mANW->queueBuffer(mANW.get(), anb, -1)
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index 2c02ba6..3542aba 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -72,7 +72,7 @@
         mSurfaceControl = mComposerClient->createSurface(
                 String8("Test Surface"), 32, 32, PIXEL_FORMAT_RGBA_8888, 0);
 
-        ASSERT_TRUE(mSurfaceControl != NULL);
+        ASSERT_TRUE(mSurfaceControl != nullptr);
         ASSERT_TRUE(mSurfaceControl->isValid());
 
         Transaction t;
@@ -81,7 +81,7 @@
                 .apply());
 
         mSurface = mSurfaceControl->getSurface();
-        ASSERT_TRUE(mSurface != NULL);
+        ASSERT_TRUE(mSurface != nullptr);
     }
 
     virtual void TearDown() {
@@ -145,7 +145,7 @@
     ASSERT_EQ(NO_ERROR, native_window_set_usage(anw.get(),
             GRALLOC_USAGE_PROTECTED));
     ASSERT_EQ(NO_ERROR, native_window_set_buffer_count(anw.get(), 3));
-    ANativeWindowBuffer* buf = 0;
+    ANativeWindowBuffer* buf = nullptr;
 
     status_t err = native_window_dequeue_buffer_and_wait(anw.get(), &buf);
     if (err) {
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index a624663..8a15e2f 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -31,14 +31,16 @@
 
 // --- InputEvent ---
 
-void InputEvent::initialize(int32_t deviceId, int32_t source) {
+void InputEvent::initialize(int32_t deviceId, int32_t source, int32_t displayId) {
     mDeviceId = deviceId;
     mSource = source;
+    mDisplayId = displayId;
 }
 
 void InputEvent::initialize(const InputEvent& from) {
     mDeviceId = from.mDeviceId;
     mSource = from.mSource;
+    mDisplayId = from.mDisplayId;
 }
 
 // --- KeyEvent ---
@@ -54,6 +56,7 @@
 void KeyEvent::initialize(
         int32_t deviceId,
         int32_t source,
+        int32_t displayId,
         int32_t action,
         int32_t flags,
         int32_t keyCode,
@@ -62,7 +65,7 @@
         int32_t repeatCount,
         nsecs_t downTime,
         nsecs_t eventTime) {
-    InputEvent::initialize(deviceId, source);
+    InputEvent::initialize(deviceId, source, displayId);
     mAction = action;
     mFlags = flags;
     mKeyCode = keyCode;
@@ -215,6 +218,7 @@
 void MotionEvent::initialize(
         int32_t deviceId,
         int32_t source,
+        int32_t displayId,
         int32_t action,
         int32_t actionButton,
         int32_t flags,
@@ -230,7 +234,7 @@
         size_t pointerCount,
         const PointerProperties* pointerProperties,
         const PointerCoords* pointerCoords) {
-    InputEvent::initialize(deviceId, source);
+    InputEvent::initialize(deviceId, source, displayId);
     mAction = action;
     mActionButton = actionButton;
     mFlags = flags;
@@ -250,7 +254,7 @@
 }
 
 void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
-    InputEvent::initialize(other->mDeviceId, other->mSource);
+    InputEvent::initialize(other->mDeviceId, other->mSource, other->mDisplayId);
     mAction = other->mAction;
     mActionButton = other->mActionButton;
     mFlags = other->mFlags;
@@ -431,6 +435,7 @@
 
     mDeviceId = parcel->readInt32();
     mSource = parcel->readInt32();
+    mDisplayId = parcel->readInt32();
     mAction = parcel->readInt32();
     mActionButton = parcel->readInt32();
     mFlags = parcel->readInt32();
@@ -480,6 +485,7 @@
 
     parcel->writeInt32(mDeviceId);
     parcel->writeInt32(mSource);
+    parcel->writeInt32(mDisplayId);
     parcel->writeInt32(mAction);
     parcel->writeInt32(mActionButton);
     parcel->writeInt32(mFlags);
diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp
index 4287abe..5d27bf6 100644
--- a/libs/input/InputDevice.cpp
+++ b/libs/input/InputDevice.cpp
@@ -175,7 +175,7 @@
             return &range;
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 void InputDeviceInfo::addSource(uint32_t source) {
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index aa0bf17..770d483 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -226,7 +226,7 @@
 
 sp<InputChannel> InputChannel::dup() const {
     int fd = ::dup(getFd());
-    return fd >= 0 ? new InputChannel(getName(), fd) : NULL;
+    return fd >= 0 ? new InputChannel(getName(), fd) : nullptr;
 }
 
 
@@ -243,6 +243,7 @@
         uint32_t seq,
         int32_t deviceId,
         int32_t source,
+        int32_t displayId,
         int32_t action,
         int32_t flags,
         int32_t keyCode,
@@ -270,6 +271,7 @@
     msg.body.key.seq = seq;
     msg.body.key.deviceId = deviceId;
     msg.body.key.source = source;
+    msg.body.key.displayId = displayId;
     msg.body.key.action = action;
     msg.body.key.flags = flags;
     msg.body.key.keyCode = keyCode;
@@ -303,13 +305,15 @@
         const PointerCoords* pointerCoords) {
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' publisher ~ publishMotionEvent: seq=%u, deviceId=%d, source=0x%x, "
+            "displayId=%" PRId32 ", "
             "action=0x%x, actionButton=0x%08x, flags=0x%x, edgeFlags=0x%x, "
             "metaState=0x%x, buttonState=0x%x, xOffset=%f, yOffset=%f, "
             "xPrecision=%f, yPrecision=%f, downTime=%" PRId64 ", eventTime=%" PRId64 ", "
             "pointerCount=%" PRIu32,
             mChannel->getName().c_str(), seq,
-            deviceId, source, action, actionButton, flags, edgeFlags, metaState, buttonState,
-            xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime, pointerCount);
+            deviceId, source, displayId, action, actionButton, flags, edgeFlags, metaState,
+            buttonState, xOffset, yOffset, xPrecision, yPrecision, downTime, eventTime,
+            pointerCount);
 #endif
 
     if (!seq) {
@@ -384,7 +388,7 @@
 
 bool InputConsumer::isTouchResamplingEnabled() {
     char value[PROPERTY_VALUE_MAX];
-    int length = property_get("ro.input.noresample", value, NULL);
+    int length = property_get("ro.input.noresample", value, nullptr);
     if (length > 0) {
         if (!strcmp("1", value)) {
             return false;
@@ -398,16 +402,14 @@
 }
 
 status_t InputConsumer::consume(InputEventFactoryInterface* factory,
-        bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent,
-        int32_t* displayId) {
+        bool consumeBatches, nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
 #if DEBUG_TRANSPORT_ACTIONS
     ALOGD("channel '%s' consumer ~ consume: consumeBatches=%s, frameTime=%" PRId64,
             mChannel->getName().c_str(), consumeBatches ? "true" : "false", frameTime);
 #endif
 
     *outSeq = 0;
-    *outEvent = NULL;
-    *displayId = -1;  // Invalid display.
+    *outEvent = nullptr;
 
     // Fetch the next input message.
     // Loop until an event can be returned or no additional events are received.
@@ -422,7 +424,7 @@
             if (result) {
                 // Consume the next batched event unless batches are being held for later.
                 if (consumeBatches || result != WOULD_BLOCK) {
-                    result = consumeBatch(factory, frameTime, outSeq, outEvent, displayId);
+                    result = consumeBatch(factory, frameTime, outSeq, outEvent);
                     if (*outEvent) {
 #if DEBUG_TRANSPORT_ACTIONS
                         ALOGD("channel '%s' consumer ~ consumed batch event, seq=%u",
@@ -466,7 +468,7 @@
                     // the previous batch right now and defer the new message until later.
                     mMsgDeferred = true;
                     status_t result = consumeSamples(factory,
-                            batch, batch.samples.size(), outSeq, outEvent, displayId);
+                            batch, batch.samples.size(), outSeq, outEvent);
                     mBatches.removeAt(batchIndex);
                     if (result) {
                         return result;
@@ -500,7 +502,7 @@
             initializeMotionEvent(motionEvent, &mMsg);
             *outSeq = mMsg.body.motion.seq;
             *outEvent = motionEvent;
-            *displayId = mMsg.body.motion.displayId;
+
 #if DEBUG_TRANSPORT_ACTIONS
             ALOGD("channel '%s' consumer ~ consumed motion event, seq=%u",
                     mChannel->getName().c_str(), *outSeq);
@@ -518,14 +520,13 @@
 }
 
 status_t InputConsumer::consumeBatch(InputEventFactoryInterface* factory,
-        nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) {
+        nsecs_t frameTime, uint32_t* outSeq, InputEvent** outEvent) {
     status_t result;
     for (size_t i = mBatches.size(); i > 0; ) {
         i--;
         Batch& batch = mBatches.editItemAt(i);
         if (frameTime < 0) {
-            result = consumeSamples(factory, batch, batch.samples.size(),
-                    outSeq, outEvent, displayId);
+            result = consumeSamples(factory, batch, batch.samples.size(), outSeq, outEvent);
             mBatches.removeAt(i);
             return result;
         }
@@ -539,11 +540,11 @@
             continue;
         }
 
-        result = consumeSamples(factory, batch, split + 1, outSeq, outEvent, displayId);
+        result = consumeSamples(factory, batch, split + 1, outSeq, outEvent);
         const InputMessage* next;
         if (batch.samples.isEmpty()) {
             mBatches.removeAt(i);
-            next = NULL;
+            next = nullptr;
         } else {
             next = &batch.samples.itemAt(0);
         }
@@ -557,7 +558,7 @@
 }
 
 status_t InputConsumer::consumeSamples(InputEventFactoryInterface* factory,
-        Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent, int32_t* displayId) {
+        Batch& batch, size_t count, uint32_t* outSeq, InputEvent** outEvent) {
     MotionEvent* motionEvent = factory->createMotionEvent();
     if (! motionEvent) return NO_MEMORY;
 
@@ -572,7 +573,6 @@
             mSeqChains.push(seqChain);
             addSample(motionEvent, &msg);
         } else {
-            *displayId = msg.body.motion.displayId;
             initializeMotionEvent(motionEvent, &msg);
         }
         chain = msg.body.motion.seq;
@@ -928,6 +928,7 @@
     event->initialize(
             msg->body.key.deviceId,
             msg->body.key.source,
+            msg->body.key.displayId,
             msg->body.key.action,
             msg->body.key.flags,
             msg->body.key.keyCode,
@@ -950,6 +951,7 @@
     event->initialize(
             msg->body.motion.deviceId,
             msg->body.motion.source,
+            msg->body.motion.displayId,
             msg->body.motion.action,
             msg->body.motion.actionButton,
             msg->body.motion.flags,
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index cba1111..26747bd 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -164,10 +164,10 @@
 
 sp<KeyCharacterMap> KeyCharacterMap::combine(const sp<KeyCharacterMap>& base,
         const sp<KeyCharacterMap>& overlay) {
-    if (overlay == NULL) {
+    if (overlay == nullptr) {
         return base;
     }
-    if (base == NULL) {
+    if (base == nullptr) {
         return overlay;
     }
 
@@ -468,7 +468,7 @@
 
         // Try to find the most general behavior that maps to this character.
         // For example, the base key behavior will usually be last in the list.
-        const Behavior* found = NULL;
+        const Behavior* found = nullptr;
         for (const Behavior* behavior = key->firstBehavior; behavior; behavior = behavior->next) {
             if (behavior->character == ch) {
                 found = behavior;
@@ -487,7 +487,7 @@
         int32_t deviceId, int32_t keyCode, int32_t metaState, bool down, nsecs_t time) {
     outEvents.push();
     KeyEvent& event = outEvents.editTop();
-    event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD,
+    event.initialize(deviceId, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
             down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
             0, keyCode, 0, metaState, 0, time, time);
 }
@@ -605,11 +605,11 @@
     map->mType = parcel->readInt32();
     size_t numKeys = parcel->readInt32();
     if (parcel->errorCheck()) {
-        return NULL;
+        return nullptr;
     }
     if (numKeys > MAX_KEYS) {
         ALOGE("Too many keys in KeyCharacterMap (%zu > %d)", numKeys, MAX_KEYS);
-        return NULL;
+        return nullptr;
     }
 
     for (size_t i = 0; i < numKeys; i++) {
@@ -617,7 +617,7 @@
         char16_t label = parcel->readInt32();
         char16_t number = parcel->readInt32();
         if (parcel->errorCheck()) {
-            return NULL;
+            return nullptr;
         }
 
         Key* key = new Key();
@@ -625,14 +625,14 @@
         key->number = number;
         map->mKeys.add(keyCode, key);
 
-        Behavior* lastBehavior = NULL;
+        Behavior* lastBehavior = nullptr;
         while (parcel->readInt32()) {
             int32_t metaState = parcel->readInt32();
             char16_t character = parcel->readInt32();
             int32_t fallbackKeyCode = parcel->readInt32();
             int32_t replacementKeyCode = parcel->readInt32();
             if (parcel->errorCheck()) {
-                return NULL;
+                return nullptr;
             }
 
             Behavior* behavior = new Behavior();
@@ -649,7 +649,7 @@
         }
 
         if (parcel->errorCheck()) {
-            return NULL;
+            return nullptr;
         }
     }
     return map;
@@ -666,7 +666,7 @@
         parcel->writeInt32(keyCode);
         parcel->writeInt32(key->label);
         parcel->writeInt32(key->number);
-        for (const Behavior* behavior = key->firstBehavior; behavior != NULL;
+        for (const Behavior* behavior = key->firstBehavior; behavior != nullptr;
                 behavior = behavior->next) {
             parcel->writeInt32(1);
             parcel->writeInt32(behavior->metaState);
@@ -683,12 +683,12 @@
 // --- KeyCharacterMap::Key ---
 
 KeyCharacterMap::Key::Key() :
-        label(0), number(0), firstBehavior(NULL) {
+        label(0), number(0), firstBehavior(nullptr) {
 }
 
 KeyCharacterMap::Key::Key(const Key& other) :
         label(other.label), number(other.number),
-        firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : NULL) {
+        firstBehavior(other.firstBehavior ? new Behavior(*other.firstBehavior) : nullptr) {
 }
 
 KeyCharacterMap::Key::~Key() {
@@ -704,11 +704,11 @@
 // --- KeyCharacterMap::Behavior ---
 
 KeyCharacterMap::Behavior::Behavior() :
-        next(NULL), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) {
+        next(nullptr), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) {
 }
 
 KeyCharacterMap::Behavior::Behavior(const Behavior& other) :
-        next(other.next ? new Behavior(*other.next) : NULL),
+        next(other.next ? new Behavior(*other.next) : nullptr),
         metaState(other.metaState), character(other.character),
         fallbackKeyCode(other.fallbackKeyCode),
         replacementKeyCode(other.replacementKeyCode) {
diff --git a/libs/input/KeyLayoutMap.cpp b/libs/input/KeyLayoutMap.cpp
index 2b2f13e..c440078 100644
--- a/libs/input/KeyLayoutMap.cpp
+++ b/libs/input/KeyLayoutMap.cpp
@@ -117,7 +117,7 @@
             return &mKeysByScanCode.valueAt(index);
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 status_t KeyLayoutMap::findScanCodesForKey(int32_t keyCode, Vector<int32_t>* outScanCodes) const {
diff --git a/libs/input/VelocityTracker.cpp b/libs/input/VelocityTracker.cpp
index c07a812..118f3aa 100644
--- a/libs/input/VelocityTracker.cpp
+++ b/libs/input/VelocityTracker.cpp
@@ -115,7 +115,7 @@
 
     // Allow the default strategy to be overridden using a system property for debugging.
     if (!strategy) {
-        int length = property_get("debug.velocitytracker.strategy", value, NULL);
+        int length = property_get("persist.input.velocitytracker.strategy", value, nullptr);
         if (length > 0) {
             strategy = value;
         } else {
@@ -139,7 +139,7 @@
 
 bool VelocityTracker::configureStrategy(const char* strategy) {
     mStrategy = createStrategy(strategy);
-    return mStrategy != NULL;
+    return mStrategy != nullptr;
 }
 
 VelocityTrackerStrategy* VelocityTracker::createStrategy(const char* strategy) {
@@ -204,7 +204,7 @@
         // time to adjust to changes in direction.
         return new LegacyVelocityTrackerStrategy();
     }
-    return NULL;
+    return nullptr;
 }
 
 void VelocityTracker::clear() {
diff --git a/libs/input/VirtualKeyMap.cpp b/libs/input/VirtualKeyMap.cpp
index 28ea717..9932973 100644
--- a/libs/input/VirtualKeyMap.cpp
+++ b/libs/input/VirtualKeyMap.cpp
@@ -47,7 +47,7 @@
 }
 
 status_t VirtualKeyMap::load(const String8& filename, VirtualKeyMap** outMap) {
-    *outMap = NULL;
+    *outMap = nullptr;
 
     Tokenizer* tokenizer;
     status_t status = Tokenizer::open(filename, &tokenizer);
diff --git a/libs/input/tests/Android.bp b/libs/input/tests/Android.bp
index aca9521..f06119f 100644
--- a/libs/input/tests/Android.bp
+++ b/libs/input/tests/Android.bp
@@ -1,7 +1,6 @@
 // Build the unit tests.
 cc_test {
     name: "libinput_tests",
-    test_per_src: true,
     srcs: [
         "InputChannel_test.cpp",
         "InputEvent_test.cpp",
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index fd3b7c8..99f83ba 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -22,6 +22,9 @@
 
 namespace android {
 
+// Default display id.
+static constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
+
 class BaseTest : public testing::Test {
 protected:
     virtual void SetUp() { }
@@ -178,13 +181,14 @@
     // Initialize and get properties.
     const nsecs_t ARBITRARY_DOWN_TIME = 1;
     const nsecs_t ARBITRARY_EVENT_TIME = 2;
-    event.initialize(2, AINPUT_SOURCE_GAMEPAD, AKEY_EVENT_ACTION_DOWN,
+    event.initialize(2, AINPUT_SOURCE_GAMEPAD, DISPLAY_ID, AKEY_EVENT_ACTION_DOWN,
             AKEY_EVENT_FLAG_FROM_SYSTEM, AKEYCODE_BUTTON_X, 121,
             AMETA_ALT_ON, 1, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME);
 
     ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event.getType());
     ASSERT_EQ(2, event.getDeviceId());
     ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_GAMEPAD), event.getSource());
+    ASSERT_EQ(DISPLAY_ID, event.getDisplayId());
     ASSERT_EQ(AKEY_EVENT_ACTION_DOWN, event.getAction());
     ASSERT_EQ(AKEY_EVENT_FLAG_FROM_SYSTEM, event.getFlags());
     ASSERT_EQ(AKEYCODE_BUTTON_X, event.getKeyCode());
@@ -197,6 +201,11 @@
     // Set source.
     event.setSource(AINPUT_SOURCE_JOYSTICK);
     ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource());
+
+    // Set display id.
+    constexpr int32_t newDisplayId = 2;
+    event.setDisplayId(newDisplayId);
+    ASSERT_EQ(newDisplayId, event.getDisplayId());
 }
 
 
@@ -248,7 +257,7 @@
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR, 26);
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR, 27);
     pointerCoords[1].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, 28);
-    event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE, 0,
+    event->initialize(2, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0,
             AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED,
             AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
             X_OFFSET, Y_OFFSET, 2.0f, 2.1f,
@@ -301,6 +310,7 @@
     ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType());
     ASSERT_EQ(2, event->getDeviceId());
     ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_TOUCHSCREEN), event->getSource());
+    ASSERT_EQ(DISPLAY_ID, event->getDisplayId());
     ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, event->getAction());
     ASSERT_EQ(AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED, event->getFlags());
     ASSERT_EQ(AMOTION_EVENT_EDGE_FLAG_TOP, event->getEdgeFlags());
@@ -434,6 +444,11 @@
     event.setSource(AINPUT_SOURCE_JOYSTICK);
     ASSERT_EQ(static_cast<int>(AINPUT_SOURCE_JOYSTICK), event.getSource());
 
+    // Set displayId.
+    constexpr int32_t newDisplayId = 2;
+    event.setDisplayId(newDisplayId);
+    ASSERT_EQ(newDisplayId, event.getDisplayId());
+
     // Set action.
     event.setAction(AMOTION_EVENT_ACTION_CANCEL);
     ASSERT_EQ(AMOTION_EVENT_ACTION_CANCEL, event.getAction());
@@ -557,7 +572,7 @@
         pointerCoords[i].setAxisValue(AMOTION_EVENT_AXIS_ORIENTATION, angle);
     }
     MotionEvent event;
-    event.initialize(0, 0, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, 0,
+    event.initialize(0, 0, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE, 0, 0, 0, 0, 0,
             0, 0, 0, 0, 0, 0, pointerCount, pointerProperties, pointerCoords);
     float originalRawX = 0 + 3;
     float originalRawY = -RADIUS + 2;
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index c532241..0788c89 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -46,12 +46,12 @@
     virtual void TearDown() {
         if (mPublisher) {
             delete mPublisher;
-            mPublisher = NULL;
+            mPublisher = nullptr;
         }
 
         if (mConsumer) {
             delete mConsumer;
-            mConsumer = NULL;
+            mConsumer = nullptr;
         }
 
         serverChannel.clear();
@@ -70,32 +70,31 @@
 void InputPublisherAndConsumerTest::PublishAndConsumeKeyEvent() {
     status_t status;
 
-    const uint32_t seq = 15;
-    const int32_t deviceId = 1;
-    const int32_t source = AINPUT_SOURCE_KEYBOARD;
-    const int32_t action = AKEY_EVENT_ACTION_DOWN;
-    const int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM;
-    const int32_t keyCode = AKEYCODE_ENTER;
-    const int32_t scanCode = 13;
-    const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
-    const int32_t repeatCount = 1;
-    const nsecs_t downTime = 3;
-    const nsecs_t eventTime = 4;
+    constexpr uint32_t seq = 15;
+    constexpr int32_t deviceId = 1;
+    constexpr int32_t source = AINPUT_SOURCE_KEYBOARD;
+    constexpr int32_t displayId = ADISPLAY_ID_DEFAULT;
+    constexpr int32_t action = AKEY_EVENT_ACTION_DOWN;
+    constexpr int32_t flags = AKEY_EVENT_FLAG_FROM_SYSTEM;
+    constexpr int32_t keyCode = AKEYCODE_ENTER;
+    constexpr int32_t scanCode = 13;
+    constexpr int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
+    constexpr int32_t repeatCount = 1;
+    constexpr nsecs_t downTime = 3;
+    constexpr nsecs_t eventTime = 4;
 
-    status = mPublisher->publishKeyEvent(seq, deviceId, source, action, flags,
+    status = mPublisher->publishKeyEvent(seq, deviceId, source, displayId, action, flags,
             keyCode, scanCode, metaState, repeatCount, downTime, eventTime);
     ASSERT_EQ(OK, status)
             << "publisher publishKeyEvent should return OK";
 
     uint32_t consumeSeq;
     InputEvent* event;
-    int32_t displayId;
-    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
-            &displayId);
+    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
     ASSERT_EQ(OK, status)
             << "consumer consume should return OK";
 
-    ASSERT_TRUE(event != NULL)
+    ASSERT_TRUE(event != nullptr)
             << "consumer should have returned non-NULL event";
     ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, event->getType())
             << "consumer should have returned a key event";
@@ -104,6 +103,7 @@
     EXPECT_EQ(seq, consumeSeq);
     EXPECT_EQ(deviceId, keyEvent->getDeviceId());
     EXPECT_EQ(source, keyEvent->getSource());
+    EXPECT_EQ(displayId, keyEvent->getDisplayId());
     EXPECT_EQ(action, keyEvent->getAction());
     EXPECT_EQ(flags, keyEvent->getFlags());
     EXPECT_EQ(keyCode, keyEvent->getKeyCode());
@@ -131,23 +131,23 @@
 void InputPublisherAndConsumerTest::PublishAndConsumeMotionEvent() {
     status_t status;
 
-    const uint32_t seq = 15;
-    const int32_t deviceId = 1;
-    const int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
-    int32_t displayId = 0;
-    const int32_t action = AMOTION_EVENT_ACTION_MOVE;
-    const int32_t actionButton = 0;
-    const int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
-    const int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
-    const int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
-    const int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY;
-    const float xOffset = -10;
-    const float yOffset = -20;
-    const float xPrecision = 0.25;
-    const float yPrecision = 0.5;
-    const nsecs_t downTime = 3;
-    const size_t pointerCount = 3;
-    const nsecs_t eventTime = 4;
+    constexpr uint32_t seq = 15;
+    constexpr int32_t deviceId = 1;
+    constexpr int32_t source = AINPUT_SOURCE_TOUCHSCREEN;
+    constexpr int32_t displayId = ADISPLAY_ID_DEFAULT;
+    constexpr int32_t action = AMOTION_EVENT_ACTION_MOVE;
+    constexpr int32_t actionButton = 0;
+    constexpr int32_t flags = AMOTION_EVENT_FLAG_WINDOW_IS_OBSCURED;
+    constexpr int32_t edgeFlags = AMOTION_EVENT_EDGE_FLAG_TOP;
+    constexpr int32_t metaState = AMETA_ALT_LEFT_ON | AMETA_ALT_ON;
+    constexpr int32_t buttonState = AMOTION_EVENT_BUTTON_PRIMARY;
+    constexpr float xOffset = -10;
+    constexpr float yOffset = -20;
+    constexpr float xPrecision = 0.25;
+    constexpr float yPrecision = 0.5;
+    constexpr nsecs_t downTime = 3;
+    constexpr size_t pointerCount = 3;
+    constexpr nsecs_t eventTime = 4;
     PointerProperties pointerProperties[pointerCount];
     PointerCoords pointerCoords[pointerCount];
     for (size_t i = 0; i < pointerCount; i++) {
@@ -176,12 +176,11 @@
 
     uint32_t consumeSeq;
     InputEvent* event;
-    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event,
-            &displayId);
+    status = mConsumer->consume(&mEventFactory, true /*consumeBatches*/, -1, &consumeSeq, &event);
     ASSERT_EQ(OK, status)
             << "consumer consume should return OK";
 
-    ASSERT_TRUE(event != NULL)
+    ASSERT_TRUE(event != nullptr)
             << "consumer should have returned non-NULL event";
     ASSERT_EQ(AINPUT_EVENT_TYPE_MOTION, event->getType())
             << "consumer should have returned a motion event";
@@ -190,6 +189,7 @@
     EXPECT_EQ(seq, consumeSeq);
     EXPECT_EQ(deviceId, motionEvent->getDeviceId());
     EXPECT_EQ(source, motionEvent->getSource());
+    EXPECT_EQ(displayId, motionEvent->getDisplayId());
     EXPECT_EQ(action, motionEvent->getAction());
     EXPECT_EQ(flags, motionEvent->getFlags());
     EXPECT_EQ(edgeFlags, motionEvent->getEdgeFlags());
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 43b6012..5242a18 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -26,6 +26,8 @@
 
 namespace android {
 
+constexpr int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT; // default display id
+
 constexpr int32_t DEFAULT_POINTER_ID = 0; // pointer ID used for manually defined tests
 
 // velocity must be in the range (1-tol)*EV <= velocity <= (1+tol)*EV
@@ -89,7 +91,7 @@
     // First sample added separately with initialize
     coords.setAxisValue(AMOTION_EVENT_AXIS_X, positions[0].x);
     coords.setAxisValue(AMOTION_EVENT_AXIS_Y, positions[0].y);
-    event->initialize(0, AINPUT_SOURCE_TOUCHSCREEN, AMOTION_EVENT_ACTION_MOVE,
+    event->initialize(0, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID, AMOTION_EVENT_ACTION_MOVE,
             0, 0, 0, 0, 0, 0, 0, 0, 0, 0, positions[0].time, 1, properties, &coords);
 
     for (size_t i = 1; i < numSamples; i++) {
diff --git a/libs/sensor/Sensor.cpp b/libs/sensor/Sensor.cpp
index a0e368c..d9a986e 100644
--- a/libs/sensor/Sensor.cpp
+++ b/libs/sensor/Sensor.cpp
@@ -318,7 +318,7 @@
         // If the sensor is protected by a permission we need to know if it is
         // a runtime one to determine whether we can use the permission cache.
         sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
-        if (binder != 0) {
+        if (binder != nullptr) {
             sp<IPermissionController> permCtrl = interface_cast<IPermissionController>(binder);
             mRequiredPermissionRuntime = permCtrl->isRuntimePermission(
                     String16(mRequiredPermission));
diff --git a/libs/sensor/SensorEventQueue.cpp b/libs/sensor/SensorEventQueue.cpp
index 6f68fb5..46ba7c6 100644
--- a/libs/sensor/SensorEventQueue.cpp
+++ b/libs/sensor/SensorEventQueue.cpp
@@ -37,7 +37,7 @@
 // ----------------------------------------------------------------------------
 
 SensorEventQueue::SensorEventQueue(const sp<ISensorEventConnection>& connection)
-    : mSensorEventConnection(connection), mRecBuffer(NULL), mAvailable(0), mConsumed(0),
+    : mSensorEventConnection(connection), mRecBuffer(nullptr), mAvailable(0), mConsumed(0),
       mNumAcksToSend(0) {
     mRecBuffer = new ASensorEvent[MAX_RECEIVE_BUFFER_EVENT_COUNT];
 }
@@ -82,9 +82,9 @@
 sp<Looper> SensorEventQueue::getLooper() const
 {
     Mutex::Autolock _l(mLock);
-    if (mLooper == 0) {
+    if (mLooper == nullptr) {
         mLooper = new Looper(true);
-        mLooper->addFd(getFd(), getFd(), ALOOPER_EVENT_INPUT, NULL, NULL);
+        mLooper->addFd(getFd(), getFd(), ALOOPER_EVENT_INPUT, nullptr, nullptr);
     }
     return mLooper;
 }
@@ -97,7 +97,7 @@
     int events;
     int32_t result;
     do {
-        result = looper->pollOnce(-1, NULL, &events, NULL);
+        result = looper->pollOnce(-1, nullptr, &events, nullptr);
         if (result == ALOOPER_POLL_ERROR) {
             ALOGE("SensorEventQueue::waitForEvent error (errno=%d)", errno);
             result = -EPIPE; // unknown error, so we make up one
diff --git a/libs/sensor/SensorManager.cpp b/libs/sensor/SensorManager.cpp
index b9ae524..5840d51 100644
--- a/libs/sensor/SensorManager.cpp
+++ b/libs/sensor/SensorManager.cpp
@@ -62,7 +62,7 @@
         // to the wrong package and stats based on app ops may be slightly off.
         if (opPackageName.size() <= 0) {
             sp<IBinder> binder = defaultServiceManager()->getService(String16("permission"));
-            if (binder != 0) {
+            if (binder != nullptr) {
                 const uid_t uid = IPCThreadState::self()->getCallingUid();
                 Vector<String16> packages;
                 interface_cast<IPermissionController>(binder)->getPackagesForUid(uid, packages);
@@ -93,7 +93,7 @@
 }
 
 SensorManager::SensorManager(const String16& opPackageName)
-    : mSensorList(0), mOpPackageName(opPackageName), mDirectConnectionHandle(1) {
+    : mSensorList(nullptr), mOpPackageName(opPackageName), mDirectConnectionHandle(1) {
     // okay we're not locked here, but it's not needed during construction
     assertStateLocked();
 }
@@ -128,13 +128,13 @@
     Mutex::Autolock _l(mLock);
     mSensorServer.clear();
     free(mSensorList);
-    mSensorList = NULL;
+    mSensorList = nullptr;
     mSensors.clear();
 }
 
 status_t SensorManager::assertStateLocked() {
     bool initSensorManager = false;
-    if (mSensorServer == NULL) {
+    if (mSensorServer == nullptr) {
         initSensorManager = true;
     } else {
         // Ping binder to check if sensorservice is alive.
@@ -164,7 +164,7 @@
         size_t count = mSensors.size();
         mSensorList =
                 static_cast<Sensor const**>(malloc(count * sizeof(Sensor*)));
-        LOG_ALWAYS_FATAL_IF(mSensorList == NULL, "mSensorList NULL");
+        LOG_ALWAYS_FATAL_IF(mSensorList == nullptr, "mSensorList NULL");
 
         for (size_t i=0 ; i<count ; i++) {
             mSensorList[i] = mSensors.array() + i;
@@ -222,7 +222,7 @@
             }
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 sp<SensorEventQueue> SensorManager::createEventQueue(String8 packageName, int mode) {
@@ -232,10 +232,10 @@
     while (assertStateLocked() == NO_ERROR) {
         sp<ISensorEventConnection> connection =
                 mSensorServer->createSensorEventConnection(packageName, mode, mOpPackageName);
-        if (connection == NULL) {
+        if (connection == nullptr) {
             // SensorService just died or the app doesn't have required permissions.
             ALOGE("createEventQueue: connection is NULL.");
-            return NULL;
+            return nullptr;
         }
         queue = new SensorEventQueue(connection);
         break;
diff --git a/libs/vr/libbufferhub/buffer_hub_client.cpp b/libs/vr/libbufferhub/buffer_hub_client.cpp
index 159f2bd..577cba9 100644
--- a/libs/vr/libbufferhub/buffer_hub_client.cpp
+++ b/libs/vr/libbufferhub/buffer_hub_client.cpp
@@ -42,11 +42,13 @@
 BufferHubBuffer::BufferHubBuffer(LocalChannelHandle channel_handle)
     : Client{pdx::default_transport::ClientChannel::Create(
           std::move(channel_handle))},
-      id_(-1) {}
+      id_(-1),
+      cid_(-1) {}
 BufferHubBuffer::BufferHubBuffer(const std::string& endpoint_path)
     : Client{pdx::default_transport::ClientChannelFactory::Create(
           endpoint_path)},
-      id_(-1) {}
+      id_(-1),
+      cid_(-1) {}
 
 BufferHubBuffer::~BufferHubBuffer() {
   if (metadata_header_ != nullptr) {
@@ -136,6 +138,7 @@
   }
 
   id_ = new_id;
+  cid_ = buffer_desc.buffer_cid();
   buffer_state_bit_ = buffer_desc.buffer_state_bit();
 
   // Note that here the buffer state is mapped from shared memory as an atomic
diff --git a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
index 0ea77c8..b71f5dc 100644
--- a/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
+++ b/libs/vr/libbufferhub/include/private/dvr/buffer_hub_client.h
@@ -107,8 +107,14 @@
   IonBuffer* buffer() { return &buffer_; }
   const IonBuffer* buffer() const { return &buffer_; }
 
+  // Gets ID of the buffer client. All BufferHubBuffer clients derived from the
+  // same buffer in bufferhubd share the same buffer id.
   int id() const { return id_; }
 
+  // Gets the channel id of the buffer client. Each BufferHubBuffer client has
+  // its system unique channel id.
+  int cid() const { return cid_; }
+
   // Returns the buffer buffer state.
   uint64_t buffer_state() { return buffer_state_->load(); };
 
@@ -170,6 +176,7 @@
   // for logging and debugging purposes only and should not be used for lookup
   // or any other functional purpose as a security precaution.
   int id_;
+  int cid_;
   uint64_t buffer_state_bit_{0ULL};
   IonBuffer buffer_;
   IonBuffer metadata_buffer_;
diff --git a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
index f4918c4..088a235 100644
--- a/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
+++ b/libs/vr/libbufferhub/include/private/dvr/bufferhub_rpc.h
@@ -164,10 +164,11 @@
  public:
   BufferDescription() = default;
   BufferDescription(const IonBuffer& buffer, const IonBuffer& metadata, int id,
-                    uint64_t buffer_state_bit,
+                    int buffer_cid, uint64_t buffer_state_bit,
                     const FileHandleType& acquire_fence_fd,
                     const FileHandleType& release_fence_fd)
       : id_(id),
+        buffer_cid_(buffer_cid),
         buffer_state_bit_(buffer_state_bit),
         buffer_(buffer, id),
         metadata_(metadata, id),
@@ -180,6 +181,9 @@
   // ID of the buffer client. All BufferHubBuffer clients derived from the same
   // buffer in bufferhubd share the same buffer id.
   int id() const { return id_; }
+  // Channel ID of the buffer client. Each BufferHubBuffer client has its system
+  // unique channel id.
+  int buffer_cid() const { return buffer_cid_; }
   // State mask of the buffer client. Each BufferHubBuffer client backed by the
   // same buffer channel has uniqued state bit among its siblings. For a
   // producer buffer the bit must be kProducerStateBit; for a consumer the bit
@@ -193,6 +197,7 @@
 
  private:
   int id_{-1};
+  int buffer_cid_{-1};
   uint64_t buffer_state_bit_{0};
   // Two IonBuffers: one for the graphic buffer and one for metadata.
   NativeBufferHandle<FileHandleType> buffer_;
@@ -202,7 +207,7 @@
   FileHandleType acquire_fence_fd_;
   FileHandleType release_fence_fd_;
 
-  PDX_SERIALIZABLE_MEMBERS(BufferDescription<FileHandleType>, id_,
+  PDX_SERIALIZABLE_MEMBERS(BufferDescription<FileHandleType>, id_, buffer_cid_,
                            buffer_state_bit_, buffer_, metadata_,
                            acquire_fence_fd_, release_fence_fd_);
 
@@ -381,6 +386,7 @@
     kOpCreateConsumerQueue,
     kOpGetQueueInfo,
     kOpProducerQueueAllocateBuffers,
+    kOpProducerQueueInsertBuffer,
     kOpProducerQueueRemoveBuffer,
     kOpConsumerQueueImportBuffers,
     // TODO(b/77153033): Separate all those RPC operations into subclasses.
@@ -430,6 +436,8 @@
                     std::vector<std::pair<LocalChannelHandle, size_t>>(
                         uint32_t width, uint32_t height, uint32_t layer_count,
                         uint32_t format, uint64_t usage, size_t buffer_count));
+  PDX_REMOTE_METHOD(ProducerQueueInsertBuffer, kOpProducerQueueInsertBuffer,
+                    size_t(int buffer_cid));
   PDX_REMOTE_METHOD(ProducerQueueRemoveBuffer, kOpProducerQueueRemoveBuffer,
                     void(size_t slot));
   PDX_REMOTE_METHOD(ConsumerQueueImportBuffers, kOpConsumerQueueImportBuffers,
diff --git a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
index 8feb1cd..1f2c517 100644
--- a/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
+++ b/libs/vr/libbufferhubqueue/buffer_hub_queue_client.cpp
@@ -524,6 +524,40 @@
   return BufferHubQueue::Enqueue({buffer, slot, 0ULL});
 }
 
+Status<size_t> ProducerQueue::InsertBuffer(
+    const std::shared_ptr<BufferProducer>& buffer) {
+  if (buffer == nullptr ||
+      !BufferHubDefs::IsBufferGained(buffer->buffer_state())) {
+    ALOGE(
+        "ProducerQueue::InsertBuffer: Can only insert a buffer when it's in "
+        "gained state.");
+    return ErrorStatus(EINVAL);
+  }
+
+  auto status_or_slot =
+      InvokeRemoteMethod<BufferHubRPC::ProducerQueueInsertBuffer>(
+          buffer->cid());
+  if (!status_or_slot) {
+    ALOGE(
+        "ProducerQueue::InsertBuffer: Failed to insert producer buffer: "
+        "buffer_cid=%d, error: %s.",
+        buffer->cid(), status_or_slot.GetErrorMessage().c_str());
+    return status_or_slot.error_status();
+  }
+
+  size_t slot = status_or_slot.get();
+
+  // Note that we are calling AddBuffer() from the base class to explicitly
+  // avoid Enqueue() the BufferProducer.
+  auto status = BufferHubQueue::AddBuffer(buffer, slot);
+  if (!status) {
+    ALOGE("ProducerQueue::InsertBuffer: Failed to add buffer: %s.",
+          status.GetErrorMessage().c_str());
+    return status.error_status();
+  }
+  return {slot};
+}
+
 Status<void> ProducerQueue::RemoveBuffer(size_t slot) {
   auto status =
       InvokeRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(slot);
diff --git a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
index 60e1c4b..df500b4 100644
--- a/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
+++ b/libs/vr/libbufferhubqueue/include/private/dvr/buffer_hub_queue_client.h
@@ -331,6 +331,13 @@
   pdx::Status<void> AddBuffer(const std::shared_ptr<BufferProducer>& buffer,
                               size_t slot);
 
+  // Inserts a ProducerBuffer into the queue. On success, the method returns the
+  // |slot| number where the new buffer gets inserted. Note that the buffer
+  // being inserted should be in Gain'ed state prior to the call and it's
+  // considered as already Dequeued when the function returns.
+  pdx::Status<size_t> InsertBuffer(
+      const std::shared_ptr<BufferProducer>& buffer);
+
   // Remove producer buffer from the queue.
   pdx::Status<void> RemoveBuffer(size_t slot) override;
 
diff --git a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
index 47a2734..2975f56 100644
--- a/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
+++ b/libs/vr/libbufferhubqueue/tests/buffer_hub_queue-test.cpp
@@ -181,6 +181,40 @@
   }
 }
 
+TEST_F(BufferHubQueueTest, TestInsertBuffer) {
+  ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
+
+  consumer_queue_ = producer_queue_->CreateConsumerQueue();
+  ASSERT_TRUE(consumer_queue_ != nullptr);
+  EXPECT_EQ(producer_queue_->capacity(), 0);
+  EXPECT_EQ(consumer_queue_->capacity(), 0);
+
+  std::shared_ptr<BufferProducer> p1 = BufferProducer::Create(
+      kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage, 0);
+  ASSERT_TRUE(p1 != nullptr);
+
+  // Inserting a posted buffer will fail.
+  DvrNativeBufferMetadata meta;
+  EXPECT_EQ(p1->PostAsync(&meta, LocalHandle()), 0);
+  auto status_or_slot = producer_queue_->InsertBuffer(p1);
+  EXPECT_FALSE(status_or_slot.ok());
+  EXPECT_EQ(status_or_slot.error(), EINVAL);
+
+  // Inserting a gained buffer will succeed.
+  std::shared_ptr<BufferProducer> p2 = BufferProducer::Create(
+      kBufferWidth, kBufferHeight, kBufferFormat, kBufferUsage);
+  ASSERT_TRUE(p2 != nullptr);
+  status_or_slot = producer_queue_->InsertBuffer(p2);
+  EXPECT_TRUE(status_or_slot.ok());
+  // This is the first buffer inserted, should take slot 0.
+  size_t slot = status_or_slot.get();
+  EXPECT_EQ(slot, 0);
+
+  // Wait and expect the consumer to kick up the newly inserted buffer.
+  WaitAndHandleOnce(consumer_queue_.get(), kTimeoutMs);
+  EXPECT_EQ(consumer_queue_->capacity(), 1ULL);
+}
+
 TEST_F(BufferHubQueueTest, TestRemoveBuffer) {
   ASSERT_TRUE(CreateProducerQueue(config_builder_.Build(), UsagePolicy{}));
   DvrNativeBufferMetadata mo;
diff --git a/libs/vr/libdisplay/Android.bp b/libs/vr/libdisplay/Android.bp
index 9c67881..8c354fb 100644
--- a/libs/vr/libdisplay/Android.bp
+++ b/libs/vr/libdisplay/Android.bp
@@ -16,8 +16,8 @@
     "display_client.cpp",
     "display_manager_client.cpp",
     "display_protocol.cpp",
-    "vsync_client.cpp",
     "shared_buffer_helpers.cpp",
+    "vsync_service.cpp",
 ]
 
 localIncludeFiles = [
diff --git a/libs/vr/libdisplay/include/private/dvr/vsync_client.h b/libs/vr/libdisplay/include/private/dvr/vsync_client.h
deleted file mode 100644
index 1eeb80e..0000000
--- a/libs/vr/libdisplay/include/private/dvr/vsync_client.h
+++ /dev/null
@@ -1,69 +0,0 @@
-#ifndef ANDROID_DVR_VSYNC_CLIENT_H_
-#define ANDROID_DVR_VSYNC_CLIENT_H_
-
-#include <stdint.h>
-
-#include <pdx/client.h>
-
-struct dvr_vsync_client {};
-
-namespace android {
-namespace dvr {
-
-/*
- * VSyncClient is a remote interface to the vsync service in displayd.
- * This class is used to wait for and retrieve information about the
- * display vsync.
- */
-class VSyncClient : public pdx::ClientBase<VSyncClient>,
-                    public dvr_vsync_client {
- public:
-  /*
-   * Wait for the next vsync signal.
-   * The timestamp (in ns) is written into *ts when ts is non-NULL.
-   */
-  int Wait(int64_t* timestamp_ns);
-
-  /*
-   * Returns the file descriptor used to communicate with the vsync system
-   * service or -1 on error.
-   */
-  int GetFd();
-
-  /*
-   * Clears the select/poll/epoll event so that subsequent calls to
-   * these will not signal until the next vsync.
-   */
-  int Acknowledge();
-
-  /*
-   * Get the timestamp of the last vsync event in ns. This call has
-   * the same side effect on events as Acknowledge(), which saves
-   * an IPC message.
-   */
-  int GetLastTimestamp(int64_t* timestamp_ns);
-
-  /*
-   * Get vsync scheduling info.
-   * Get the estimated timestamp of the next GPU lens warp preemption event in
-   * ns. Also returns the corresponding vsync count that the next lens warp
-   * operation will target. This call has the same side effect on events as
-   * Acknowledge(), which saves an IPC message.
-   */
-  int GetSchedInfo(int64_t* vsync_period_ns, int64_t* next_timestamp_ns,
-                   uint32_t* next_vsync_count);
-
- private:
-  friend BASE;
-
-  VSyncClient();
-  explicit VSyncClient(long timeout_ms);
-
-  VSyncClient(const VSyncClient&) = delete;
-  void operator=(const VSyncClient&) = delete;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_VSYNC_CLIENT_H_
diff --git a/libs/vr/libdisplay/include/private/dvr/vsync_service.h b/libs/vr/libdisplay/include/private/dvr/vsync_service.h
new file mode 100644
index 0000000..152464a
--- /dev/null
+++ b/libs/vr/libdisplay/include/private/dvr/vsync_service.h
@@ -0,0 +1,65 @@
+#ifndef ANDROID_DVR_VSYNC_SERVICE_H_
+#define ANDROID_DVR_VSYNC_SERVICE_H_
+
+#include <binder/IInterface.h>
+
+namespace android {
+namespace dvr {
+
+class IVsyncCallback : public IInterface {
+ public:
+  DECLARE_META_INTERFACE(VsyncCallback)
+
+  enum {
+    ON_VSYNC = IBinder::FIRST_CALL_TRANSACTION
+  };
+
+  virtual status_t onVsync(int64_t vsync_timestamp) = 0;
+};
+
+class BnVsyncCallback : public BnInterface<IVsyncCallback> {
+ public:
+  virtual status_t onTransact(uint32_t code, const Parcel& data,
+                              Parcel* reply, uint32_t flags = 0);
+};
+
+// Register a callback with IVsyncService to be notified of vsync events and
+// timestamps. There's also a shared memory vsync buffer defined in
+// dvr_shared_buffers.h. IVsyncService has advantages over the vsync shared
+// memory buffer that make it preferable in certain situations:
+//
+// 1. The shared memory buffer lifetime is controlled by VrCore. IVsyncService
+// is always available as long as surface flinger is running.
+//
+// 2. IVsyncService will make a binder callback when a vsync event occurs. This
+// allows the client to not write code to implement periodic "get the latest
+// vsync" calls, which is necessary with the vsync shared memory buffer.
+//
+// 3. The IVsyncService provides the real vsync timestamp reported by hardware
+// composer, whereas the vsync shared memory buffer only has predicted vsync
+// times.
+class IVsyncService : public IInterface {
+public:
+  DECLARE_META_INTERFACE(VsyncService)
+
+  static const char* GetServiceName() { return "vrflinger_vsync"; }
+
+  enum {
+    REGISTER_CALLBACK = IBinder::FIRST_CALL_TRANSACTION,
+    UNREGISTER_CALLBACK
+  };
+
+  virtual status_t registerCallback(const sp<IVsyncCallback> callback) = 0;
+  virtual status_t unregisterCallback(const sp<IVsyncCallback> callback) = 0;
+};
+
+class BnVsyncService : public BnInterface<IVsyncService> {
+ public:
+  virtual status_t onTransact(uint32_t code, const Parcel& data,
+                              Parcel* reply, uint32_t flags = 0);
+};
+
+}  // namespace dvr
+}  // namespace android
+
+#endif  // ANDROID_DVR_VSYNC_SERVICE_H_
diff --git a/libs/vr/libdisplay/vsync_client.cpp b/libs/vr/libdisplay/vsync_client.cpp
deleted file mode 100644
index bc6cf6c..0000000
--- a/libs/vr/libdisplay/vsync_client.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-#include "include/private/dvr/vsync_client.h"
-
-#include <log/log.h>
-
-#include <pdx/default_transport/client_channel_factory.h>
-#include <private/dvr/display_protocol.h>
-
-using android::dvr::display::VSyncProtocol;
-using android::pdx::Transaction;
-
-namespace android {
-namespace dvr {
-
-VSyncClient::VSyncClient(long timeout_ms)
-    : BASE(pdx::default_transport::ClientChannelFactory::Create(
-               VSyncProtocol::kClientPath),
-           timeout_ms) {}
-
-VSyncClient::VSyncClient()
-    : BASE(pdx::default_transport::ClientChannelFactory::Create(
-          VSyncProtocol::kClientPath)) {}
-
-int VSyncClient::Wait(int64_t* timestamp_ns) {
-  auto status = InvokeRemoteMethod<VSyncProtocol::Wait>();
-  if (!status) {
-    ALOGE("VSyncClient::Wait: Failed to wait for vsync: %s",
-          status.GetErrorMessage().c_str());
-    return -status.error();
-  }
-
-  if (timestamp_ns != nullptr) {
-    *timestamp_ns = status.get();
-  }
-  return 0;
-}
-
-int VSyncClient::GetFd() { return event_fd(); }
-
-int VSyncClient::GetLastTimestamp(int64_t* timestamp_ns) {
-  auto status = InvokeRemoteMethod<VSyncProtocol::GetLastTimestamp>();
-  if (!status) {
-    ALOGE("VSyncClient::GetLastTimestamp: Failed to get vsync timestamp: %s",
-          status.GetErrorMessage().c_str());
-    return -status.error();
-  }
-  *timestamp_ns = status.get();
-  return 0;
-}
-
-int VSyncClient::GetSchedInfo(int64_t* vsync_period_ns, int64_t* timestamp_ns,
-                              uint32_t* next_vsync_count) {
-  if (!vsync_period_ns || !timestamp_ns || !next_vsync_count)
-    return -EINVAL;
-
-  auto status = InvokeRemoteMethod<VSyncProtocol::GetSchedInfo>();
-  if (!status) {
-    ALOGE("VSyncClient::GetSchedInfo:: Failed to get warp timestamp: %s",
-          status.GetErrorMessage().c_str());
-    return -status.error();
-  }
-
-  *vsync_period_ns = status.get().vsync_period_ns;
-  *timestamp_ns = status.get().timestamp_ns;
-  *next_vsync_count = status.get().next_vsync_count;
-  return 0;
-}
-
-int VSyncClient::Acknowledge() {
-  auto status = InvokeRemoteMethod<VSyncProtocol::Acknowledge>();
-  ALOGE_IF(!status, "VSuncClient::Acknowledge: Failed to ack vsync because: %s",
-           status.GetErrorMessage().c_str());
-  return ReturnStatusOrError(status);
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libdisplay/vsync_service.cpp b/libs/vr/libdisplay/vsync_service.cpp
new file mode 100644
index 0000000..43b1196
--- /dev/null
+++ b/libs/vr/libdisplay/vsync_service.cpp
@@ -0,0 +1,146 @@
+#include "include/private/dvr/vsync_service.h"
+
+#include <binder/Parcel.h>
+#include <log/log.h>
+
+namespace android {
+namespace dvr {
+
+status_t BnVsyncCallback::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+  switch (code) {
+    case ON_VSYNC: {
+      CHECK_INTERFACE(IVsyncCallback, data, reply);
+      int64_t vsync_timestamp = 0;
+      status_t result = data.readInt64(&vsync_timestamp);
+      if (result != NO_ERROR) {
+        ALOGE("onVsync failed to readInt64: %d", result);
+        return result;
+      }
+      onVsync(vsync_timestamp);
+      return NO_ERROR;
+    }
+    default: {
+      return BBinder::onTransact(code, data, reply, flags);
+    }
+  }
+}
+
+class BpVsyncCallback : public BpInterface<IVsyncCallback> {
+public:
+  explicit BpVsyncCallback(const sp<IBinder>& impl)
+      : BpInterface<IVsyncCallback>(impl) {}
+  virtual ~BpVsyncCallback() {}
+
+  virtual status_t onVsync(int64_t vsync_timestamp) {
+    Parcel data, reply;
+    status_t result = data.writeInterfaceToken(
+        IVsyncCallback::getInterfaceDescriptor());
+    if (result != NO_ERROR) {
+      ALOGE("onVsync failed to writeInterfaceToken: %d", result);
+      return result;
+    }
+    result = data.writeInt64(vsync_timestamp);
+    if (result != NO_ERROR) {
+      ALOGE("onVsync failed to writeInt64: %d", result);
+      return result;
+    }
+    result = remote()->transact(
+        BnVsyncCallback::ON_VSYNC, data, &reply, TF_ONE_WAY);
+    if (result != NO_ERROR) {
+      ALOGE("onVsync failed to transact: %d", result);
+      return result;
+    }
+    return result;
+  }
+};
+
+IMPLEMENT_META_INTERFACE(VsyncCallback, "android.dvr.IVsyncCallback");
+
+
+status_t BnVsyncService::onTransact(
+    uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
+  switch (code) {
+    case REGISTER_CALLBACK: {
+      CHECK_INTERFACE(IVsyncService, data, reply);
+      sp<IBinder> callback;
+      status_t result = data.readStrongBinder(&callback);
+      if (result != NO_ERROR) {
+        ALOGE("registerCallback failed to readStrongBinder: %d", result);
+        return result;
+      }
+      registerCallback(interface_cast<IVsyncCallback>(callback));
+      return NO_ERROR;
+    }
+    case UNREGISTER_CALLBACK: {
+      CHECK_INTERFACE(IVsyncService, data, reply);
+      sp<IBinder> callback;
+      status_t result = data.readStrongBinder(&callback);
+      if (result != NO_ERROR) {
+        ALOGE("unregisterCallback failed to readStrongBinder: %d", result);
+        return result;
+      }
+      unregisterCallback(interface_cast<IVsyncCallback>(callback));
+      return NO_ERROR;
+    }
+    default: {
+      return BBinder::onTransact(code, data, reply, flags);
+    }
+  }
+}
+
+class BpVsyncService : public BpInterface<IVsyncService> {
+public:
+  explicit BpVsyncService(const sp<IBinder>& impl)
+      : BpInterface<IVsyncService>(impl) {}
+  virtual ~BpVsyncService() {}
+
+  virtual status_t registerCallback(const sp<IVsyncCallback> callback) {
+    Parcel data, reply;
+    status_t result = data.writeInterfaceToken(
+        IVsyncService::getInterfaceDescriptor());
+    if (result != NO_ERROR) {
+      ALOGE("registerCallback failed to writeInterfaceToken: %d", result);
+      return result;
+    }
+    result = data.writeStrongBinder(IInterface::asBinder(callback));
+    if (result != NO_ERROR) {
+      ALOGE("registerCallback failed to writeStrongBinder: %d", result);
+      return result;
+    }
+    result = remote()->transact(
+        BnVsyncService::REGISTER_CALLBACK, data, &reply);
+    if (result != NO_ERROR) {
+      ALOGE("registerCallback failed to transact: %d", result);
+      return result;
+    }
+    return result;
+  }
+
+  virtual status_t unregisterCallback(const sp<IVsyncCallback> callback) {
+    Parcel data, reply;
+    status_t result = data.writeInterfaceToken(
+        IVsyncService::getInterfaceDescriptor());
+    if (result != NO_ERROR) {
+      ALOGE("unregisterCallback failed to writeInterfaceToken: %d", result);
+      return result;
+    }
+    result = data.writeStrongBinder(IInterface::asBinder(callback));
+    if (result != NO_ERROR) {
+      ALOGE("unregisterCallback failed to writeStrongBinder: %d", result);
+      return result;
+    }
+    result = remote()->transact(
+        BnVsyncService::UNREGISTER_CALLBACK, data, &reply);
+    if (result != NO_ERROR) {
+      ALOGE("unregisterCallback failed to transact: %d", result);
+      return result;
+    }
+    return result;
+  }
+};
+
+IMPLEMENT_META_INTERFACE(VsyncService, "android.dvr.IVsyncService");
+
+}  // namespace dvr
+}  // namespace android
diff --git a/libs/vr/libdvr/Android.bp b/libs/vr/libdvr/Android.bp
index 16906f5..3829951 100644
--- a/libs/vr/libdvr/Android.bp
+++ b/libs/vr/libdvr/Android.bp
@@ -19,7 +19,14 @@
     vendor_available: true,
 }
 
+cc_library_headers {
+    name: "libdvr_private_headers",
+    export_include_dirs: ["."],
+    vendor_available: false,
+}
+
 cflags = [
+    "-DDVR_TRACKING_IMPLEMENTED=0",
     "-DLOG_TAG=\"libdvr\"",
     "-DTRACE=0",
     "-Wall",
@@ -36,7 +43,7 @@
     "dvr_performance.cpp",
     "dvr_pose.cpp",
     "dvr_surface.cpp",
-    "dvr_vsync.cpp",
+    "dvr_tracking.cpp",
 ]
 
 static_libs = [
diff --git a/libs/vr/libdvr/dvr_api.cpp b/libs/vr/libdvr/dvr_api.cpp
index d14f040..e099f6a 100644
--- a/libs/vr/libdvr/dvr_api.cpp
+++ b/libs/vr/libdvr/dvr_api.cpp
@@ -12,6 +12,7 @@
 #include <dvr/dvr_display_manager.h>
 #include <dvr/dvr_performance.h>
 #include <dvr/dvr_surface.h>
+#include <dvr/dvr_tracking.h>
 #include <dvr/dvr_vsync.h>
 
 // Headers not yet moved into libdvr.
diff --git a/libs/vr/libdvr/dvr_buffer_queue.cpp b/libs/vr/libdvr/dvr_buffer_queue.cpp
index 74cee3f..571558a 100644
--- a/libs/vr/libdvr/dvr_buffer_queue.cpp
+++ b/libs/vr/libdvr/dvr_buffer_queue.cpp
@@ -171,12 +171,12 @@
 int DvrWriteBufferQueue::PostBuffer(DvrWriteBuffer* write_buffer,
                                     const DvrNativeBufferMetadata* meta,
                                     int ready_fence_fd) {
+  // Some basic sanity checks before we put the buffer back into a slot.
+  size_t slot = static_cast<size_t>(write_buffer->slot);
   LOG_FATAL_IF(
       (write_buffers->slot < 0 || write_buffers->slot >= write_buffers_.size()),
       "DvrWriteBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
 
-  // Some basic sanity checks before we put the buffer back into a slot.
-  size_t slot = static_cast<size_t>(write_buffer->slot);
   if (write_buffers_[slot] != nullptr) {
     ALOGE("DvrWriteBufferQueue::PostBuffer: Slot is not empty: %zu", slot);
     return -EINVAL;
@@ -374,12 +374,12 @@
 int DvrReadBufferQueue::ReleaseBuffer(DvrReadBuffer* read_buffer,
                                       const DvrNativeBufferMetadata* meta,
                                       int release_fence_fd) {
+  // Some basic sanity checks before we put the buffer back into a slot.
+  size_t slot = static_cast<size_t>(read_buffer->slot);
   LOG_FATAL_IF(
       (read_buffers->slot < 0 || read_buffers->slot >= read_buffers_size()),
       "DvrReadBufferQueue::ReleaseBuffer: Invalid slot: %zu", slot);
 
-  // Some basic sanity checks before we put the buffer back into a slot.
-  size_t slot = static_cast<size_t>(read_buffer->slot);
   if (read_buffers_[slot] != nullptr) {
     ALOGE("DvrReadBufferQueue::ReleaseBuffer: Slot is not empty: %zu", slot);
     return -EINVAL;
diff --git a/libs/vr/libdvr/dvr_tracking.cpp b/libs/vr/libdvr/dvr_tracking.cpp
new file mode 100644
index 0000000..73addc9
--- /dev/null
+++ b/libs/vr/libdvr/dvr_tracking.cpp
@@ -0,0 +1,82 @@
+#include "include/dvr/dvr_tracking.h"
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#if !DVR_TRACKING_IMPLEMENTED
+
+extern "C" {
+
+// This file provides the stub implementation of dvrTrackingXXX APIs. On
+// platforms that implement these APIs, set -DDVR_TRACKING_IMPLEMENTED=1 in the
+// build file.
+int dvrTrackingCameraCreate(DvrTrackingCamera**) {
+  ALOGE("dvrTrackingCameraCreate is not implemented.");
+  return -ENOSYS;
+}
+
+void dvrTrackingCameraDestroy(DvrTrackingCamera*) {
+  ALOGE("dvrTrackingCameraDestroy is not implemented.");
+}
+
+int dvrTrackingCameraStart(DvrTrackingCamera*, DvrWriteBufferQueue*) {
+  ALOGE("dvrTrackingCameraCreate is not implemented.");
+  return -ENOSYS;
+}
+
+int dvrTrackingCameraStop(DvrTrackingCamera*) {
+  ALOGE("dvrTrackingCameraCreate is not implemented.");
+  return -ENOSYS;
+}
+
+int dvrTrackingFeatureExtractorCreate(DvrTrackingFeatureExtractor**) {
+  ALOGE("dvrTrackingFeatureExtractorCreate is not implemented.");
+  return -ENOSYS;
+}
+
+void dvrTrackingFeatureExtractorDestroy(DvrTrackingFeatureExtractor*) {
+  ALOGE("dvrTrackingFeatureExtractorDestroy is not implemented.");
+}
+
+int dvrTrackingFeatureExtractorStart(DvrTrackingFeatureExtractor*,
+                                     DvrTrackingFeatureCallback, void*) {
+  ALOGE("dvrTrackingFeatureExtractorCreate is not implemented.");
+  return -ENOSYS;
+}
+
+int dvrTrackingFeatureExtractorStop(DvrTrackingFeatureExtractor*) {
+  ALOGE("dvrTrackingFeatureExtractorCreate is not implemented.");
+  return -ENOSYS;
+}
+
+int dvrTrackingFeatureExtractorProcessBuffer(DvrTrackingFeatureExtractor*,
+                                             DvrReadBuffer*,
+                                             const DvrTrackingBufferMetadata*,
+                                             bool*) {
+  ALOGE("dvrTrackingFeatureExtractorProcessBuffer is not implemented.");
+  return -ENOSYS;
+}
+
+int dvrTrackingSensorsCreate(DvrTrackingSensors**, const char*) {
+  ALOGE("dvrTrackingSensorsCreate is not implemented.");
+  return -ENOSYS;
+}
+
+void dvrTrackingSensorsDestroy(DvrTrackingSensors*) {
+  ALOGE("dvrTrackingSensorsDestroy is not implemented.");
+}
+
+int dvrTrackingSensorsStart(DvrTrackingSensors*, DvrTrackingSensorEventCallback,
+                            void*) {
+  ALOGE("dvrTrackingStart is not implemented.");
+  return -ENOSYS;
+}
+
+int dvrTrackingSensorsStop(DvrTrackingSensors*) {
+  ALOGE("dvrTrackingStop is not implemented.");
+  return -ENOSYS;
+}
+
+}  // extern "C"
+
+#endif  // DVR_TRACKING_IMPLEMENTED
diff --git a/libs/vr/libdvr/dvr_vsync.cpp b/libs/vr/libdvr/dvr_vsync.cpp
deleted file mode 100644
index 099240e..0000000
--- a/libs/vr/libdvr/dvr_vsync.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-#include "include/dvr/dvr_vsync.h"
-
-#include <utils/Log.h>
-
-#include <private/dvr/vsync_client.h>
-
-extern "C" {
-
-struct DvrVSyncClient {
-  std::unique_ptr<android::dvr::VSyncClient> client;
-};
-
-int dvrVSyncClientCreate(DvrVSyncClient** client_out) {
-  auto client = android::dvr::VSyncClient::Create();
-  if (!client) {
-    ALOGE("dvrVSyncClientCreate: Failed to create vsync client!");
-    return -EIO;
-  }
-
-  *client_out = new DvrVSyncClient{std::move(client)};
-  return 0;
-}
-
-void dvrVSyncClientDestroy(DvrVSyncClient* client) { delete client; }
-
-int dvrVSyncClientGetSchedInfo(DvrVSyncClient* client, int64_t* vsync_period_ns,
-                               int64_t* next_timestamp_ns,
-                               uint32_t* next_vsync_count) {
-  return client->client->GetSchedInfo(vsync_period_ns, next_timestamp_ns,
-                                      next_vsync_count);
-}
-
-}  // extern "C"
diff --git a/libs/vr/libdvr/include/dvr/dvr_api.h b/libs/vr/libdvr/include/dvr/dvr_api.h
index 80ffc82..fef8512 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api.h
@@ -10,6 +10,7 @@
 #include <dvr/dvr_display_types.h>
 #include <dvr/dvr_hardware_composer_types.h>
 #include <dvr/dvr_pose.h>
+#include <dvr/dvr_tracking_types.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -50,6 +51,12 @@
 typedef struct DvrSurfaceAttributeValue DvrSurfaceAttributeValue;
 typedef struct DvrSurfaceAttribute DvrSurfaceAttribute;
 
+typedef struct DvrReadBuffer DvrReadBuffer;
+typedef struct DvrTrackingCamera DvrTrackingCamera;
+typedef struct DvrTrackingFeatureExtractor DvrTrackingFeatureExtractor;
+typedef struct DvrTrackingSensors DvrTrackingSensors;
+typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
+
 // Note: To avoid breaking others during active development, only modify this
 // struct by appending elements to the end.
 // If you do feel we should to re-arrange or remove elements, please make a
@@ -367,6 +374,38 @@
 typedef int (*DvrPerformanceSetSchedulerPolicyPtr)(
     pid_t task_id, const char* scheduler_policy);
 
+// dvr_tracking.h
+typedef int (*DvrTrackingCameraCreatePtr)(DvrTrackingCamera** out_camera);
+typedef void (*DvrTrackingCameraDestroyPtr)(DvrTrackingCamera* camera);
+typedef int (*DvrTrackingCameraStartPtr)(DvrTrackingCamera* camera,
+                                         DvrWriteBufferQueue* write_queue);
+typedef int (*DvrTrackingCameraStopPtr)(DvrTrackingCamera* camera);
+
+typedef int (*DvrTrackingFeatureExtractorCreatePtr)(
+    DvrTrackingFeatureExtractor** out_extractor);
+typedef void (*DvrTrackingFeatureExtractorDestroyPtr)(
+    DvrTrackingFeatureExtractor* extractor);
+typedef void (*DvrTrackingFeatureCallback)(void* context,
+                                           const DvrTrackingFeatures* event);
+typedef int (*DvrTrackingFeatureExtractorStartPtr)(
+    DvrTrackingFeatureExtractor* extractor,
+    DvrTrackingFeatureCallback callback, void* context);
+typedef int (*DvrTrackingFeatureExtractorStopPtr)(
+    DvrTrackingFeatureExtractor* extractor);
+typedef int (*DvrTrackingFeatureExtractorProcessBufferPtr)(
+    DvrTrackingFeatureExtractor* extractor, DvrReadBuffer* buffer,
+    const DvrTrackingBufferMetadata* metadata, bool* out_skipped);
+
+typedef void (*DvrTrackingSensorEventCallback)(void* context,
+                                               DvrTrackingSensorEvent* event);
+typedef int (*DvrTrackingSensorsCreatePtr)(DvrTrackingSensors** out_sensors,
+                                           const char* mode);
+typedef void (*DvrTrackingSensorsDestroyPtr)(DvrTrackingSensors* sensors);
+typedef int (*DvrTrackingSensorsStartPtr)(
+    DvrTrackingSensors* sensors, DvrTrackingSensorEventCallback callback,
+    void* context);
+typedef int (*DvrTrackingSensorsStopPtr)(DvrTrackingSensors* sensors);
+
 // The buffer metadata that an Android Surface (a.k.a. ANativeWindow)
 // will populate. A DvrWriteBufferQueue must be created with this metadata iff
 // ANativeWindow access is needed. Please do not remove, modify, or reorder
diff --git a/libs/vr/libdvr/include/dvr/dvr_api_entries.h b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
index f0d8ec6..3006b61 100644
--- a/libs/vr/libdvr/include/dvr/dvr_api_entries.h
+++ b/libs/vr/libdvr/include/dvr/dvr_api_entries.h
@@ -85,9 +85,9 @@
 DVR_V1_API_ENTRY(ReadBufferQueueHandleEvents);
 
 // V-Sync client
-DVR_V1_API_ENTRY(VSyncClientCreate);
-DVR_V1_API_ENTRY(VSyncClientDestroy);
-DVR_V1_API_ENTRY(VSyncClientGetSchedInfo);
+DVR_V1_API_ENTRY_DEPRECATED(VSyncClientCreate);
+DVR_V1_API_ENTRY_DEPRECATED(VSyncClientDestroy);
+DVR_V1_API_ENTRY_DEPRECATED(VSyncClientGetSchedInfo);
 
 // Display surface
 DVR_V1_API_ENTRY(SurfaceCreate);
@@ -181,3 +181,20 @@
 DVR_V1_API_ENTRY(PoseClientGetDataReader);
 DVR_V1_API_ENTRY(PoseClientDataCapture);
 DVR_V1_API_ENTRY(PoseClientDataReaderDestroy);
+
+// Tracking
+DVR_V1_API_ENTRY(TrackingCameraCreate);
+DVR_V1_API_ENTRY(TrackingCameraDestroy);
+DVR_V1_API_ENTRY(TrackingCameraStart);
+DVR_V1_API_ENTRY(TrackingCameraStop);
+
+DVR_V1_API_ENTRY(TrackingFeatureExtractorCreate);
+DVR_V1_API_ENTRY(TrackingFeatureExtractorDestroy);
+DVR_V1_API_ENTRY(TrackingFeatureExtractorStart);
+DVR_V1_API_ENTRY(TrackingFeatureExtractorStop);
+DVR_V1_API_ENTRY(TrackingFeatureExtractorProcessBuffer);
+
+DVR_V1_API_ENTRY(TrackingSensorsCreate);
+DVR_V1_API_ENTRY(TrackingSensorsDestroy);
+DVR_V1_API_ENTRY(TrackingSensorsStart);
+DVR_V1_API_ENTRY(TrackingSensorsStop);
diff --git a/libs/vr/libdvr/include/dvr/dvr_deleter.h b/libs/vr/libdvr/include/dvr/dvr_deleter.h
index 943384f..fe59d1f 100644
--- a/libs/vr/libdvr/include/dvr/dvr_deleter.h
+++ b/libs/vr/libdvr/include/dvr/dvr_deleter.h
@@ -20,7 +20,6 @@
 typedef struct DvrSurface DvrSurface;
 typedef struct DvrHwcClient DvrHwcClient;
 typedef struct DvrHwcFrame DvrHwcFrame;
-typedef struct DvrVSyncClient DvrVSyncClient;
 
 void dvrBufferDestroy(DvrBuffer* buffer);
 void dvrReadBufferDestroy(DvrReadBuffer* read_buffer);
@@ -32,7 +31,6 @@
 void dvrSurfaceDestroy(DvrSurface* surface);
 void dvrHwcClientDestroy(DvrHwcClient* client);
 void dvrHwcFrameDestroy(DvrHwcFrame* frame);
-void dvrVSyncClientDestroy(DvrVSyncClient* client);
 
 __END_DECLS
 
@@ -55,7 +53,6 @@
   void operator()(DvrSurface* p) { dvrSurfaceDestroy(p); }
   void operator()(DvrHwcClient* p) { dvrHwcClientDestroy(p); }
   void operator()(DvrHwcFrame* p) { dvrHwcFrameDestroy(p); }
-  void operator()(DvrVSyncClient* p) { dvrVSyncClientDestroy(p); }
 };
 
 // Helper to define unique pointers for DVR object types.
@@ -73,7 +70,6 @@
 using UniqueDvrSurface = MakeUniqueDvrPointer<DvrSurface>;
 using UniqueDvrHwcClient = MakeUniqueDvrPointer<DvrHwcClient>;
 using UniqueDvrHwcFrame = MakeUniqueDvrPointer<DvrHwcFrame>;
-using UniqueDvrVSyncClient = MakeUniqueDvrPointer<DvrVSyncClient>;
 
 // TODO(eieio): Add an adapter for std::shared_ptr that injects the deleter into
 // the relevant constructors.
diff --git a/libs/vr/libdvr/include/dvr/dvr_tracking.h b/libs/vr/libdvr/include/dvr/dvr_tracking.h
new file mode 100644
index 0000000..5e388f3
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_tracking.h
@@ -0,0 +1,185 @@
+#ifndef ANDROID_DVR_TRACKING_H_
+#define ANDROID_DVR_TRACKING_H_
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+#include <dvr/dvr_tracking_types.h>
+
+__BEGIN_DECLS
+
+typedef struct DvrReadBuffer DvrReadBuffer;
+typedef struct DvrTrackingCamera DvrTrackingCamera;
+typedef struct DvrTrackingFeatureExtractor DvrTrackingFeatureExtractor;
+typedef struct DvrTrackingSensors DvrTrackingSensors;
+typedef struct DvrWriteBufferQueue DvrWriteBufferQueue;
+
+// The callback for DvrTrackingFeatureExtractor that will deliver the feature
+// events. This callback is passed to dvrTrackingFeatureExtractorStart.
+typedef void (*DvrTrackingFeatureCallback)(void* context,
+                                           const DvrTrackingFeatures* event);
+
+// The callback for DvrTrackingSensors session that will deliver the events.
+// This callback is passed to dvrTrackingSensorsStart.
+typedef void (*DvrTrackingSensorEventCallback)(void* context,
+                                               DvrTrackingSensorEvent* event);
+
+// Creates a DvrTrackingCamera session.
+//
+// On creation, the session is not in operating mode. Client code must call
+// dvrTrackingCameraStart to bootstrap the underlying camera stack.
+//
+// There is no plan to expose camera configuration through this API. All camera
+// parameters are determined by the system optimized for better tracking
+// results. See b/78662281 for detailed deprecation plan of this API and the
+// Stage 2 of VR tracking data source refactoring.
+//
+// @param out_camera The pointer of a DvrTrackingCamera will be filled here if
+//     the method call succeeds.
+// @return Zero on success, or negative error code.
+int dvrTrackingCameraCreate(DvrTrackingCamera** out_camera);
+
+// Destroys a DvrTrackingCamera handle.
+//
+// @param camera The DvrTrackingCamera of interest.
+void dvrTrackingCameraDestroy(DvrTrackingCamera* camera);
+
+// Starts the DvrTrackingCamera.
+//
+// On successful return, all DvrReadBufferQueue's associated with the given
+// write_queue will start to receive buffers from the camera stack. Note that
+// clients of this API should not assume the buffer dimension, format, and/or
+// usage of the outcoming buffers, as they are governed by the underlying camera
+// logic. Also note that it's the client's responsibility to consume buffers
+// from DvrReadBufferQueue on time and return them back to the producer;
+// otherwise the camera stack might be blocked.
+//
+// @param camera The DvrTrackingCamera of interest.
+// @param write_queue A DvrWriteBufferQueue that the camera stack can use to
+//     populate the buffer into. The queue must be empty and the camera stack
+//     will request buffer allocation with proper buffer dimension, format, and
+//     usage. Note that the write queue must be created with user_metadata_size
+//     set to sizeof(DvrTrackingBufferMetadata). On success, the write_queue
+//     handle will become invalid and the ownership of the queue handle will be
+//     transferred into the camera; otherwise, the write_queue handle will keep
+//     untouched and the caller still has the ownership.
+// @return Zero on success, or negative error code.
+int dvrTrackingCameraStart(DvrTrackingCamera* camera,
+                           DvrWriteBufferQueue* write_queue);
+
+// Stops the DvrTrackingCamera.
+//
+// On successful return, the DvrWriteBufferQueue set during
+// dvrTrackingCameraStart will stop getting new buffers from the camera stack.
+//
+// @param camera The DvrTrackingCamera of interest.
+// @return Zero on success, or negative error code.
+int dvrTrackingCameraStop(DvrTrackingCamera* camera);
+
+// Creates a DvrTrackingSensors session.
+//
+// This will initialize but not start device sensors (gyro / accel). Upon
+// successfull creation, the clients can call dvrTrackingSensorsStart to start
+// receiving sensor events.
+//
+// @param out_sensors The pointer of a DvrTrackingSensors will be filled here if
+//     the method call succeeds.
+// @param mode The sensor mode.
+//        mode="ndk": Use the Android NDK.
+//        mode="direct": Use direct mode sensors (lower latency).
+// @return Zero on success, or negative error code.
+int dvrTrackingSensorsCreate(DvrTrackingSensors** out_sensors,
+                             const char* mode);
+
+// Destroys a DvrTrackingSensors session.
+//
+// @param sensors The DvrTrackingSensors struct to destroy.
+void dvrTrackingSensorsDestroy(DvrTrackingSensors* sensors);
+
+// Starts the tracking sensor session.
+//
+// This will start the device sensors and start pumping the feature and sensor
+// events as they arrive.
+//
+// @param client A tracking client created by dvrTrackingSensorsCreate.
+// @param context A client supplied pointer that will be passed to the callback.
+// @param callback A callback that will receive the sensor events on an
+// arbitrary thread.
+// @return Zero on success, or negative error code.
+int dvrTrackingSensorsStart(DvrTrackingSensors* sensors,
+                            DvrTrackingSensorEventCallback callback,
+                            void* context);
+
+// Stops a DvrTrackingSensors session.
+//
+// This will stop the device sensors. dvrTrackingSensorsStart can be called to
+// restart them again.
+//
+// @param client A tracking client created by dvrTrackingClientCreate.
+// @return Zero on success, or negative error code.
+int dvrTrackingSensorsStop(DvrTrackingSensors* sensors);
+
+// Creates a tracking feature extractor.
+//
+// This will initialize but not start the feature extraction session. Upon
+// successful creation, the client can call dvrTrackingFeatureExtractorStart to
+// start receiving features.
+//
+// @param out_extractor The pointer of a DvrTrackingFeatureExtractor will be
+//     filled here if the method call succeeds.
+int dvrTrackingFeatureExtractorCreate(
+    DvrTrackingFeatureExtractor** out_extractor);
+
+// Destroys a tracking feature extractor.
+//
+// @param extractor The DvrTrackingFeatureExtractor to destroy.
+void dvrTrackingFeatureExtractorDestroy(DvrTrackingFeatureExtractor* extractor);
+
+// Starts the tracking feature extractor.
+//
+// This will start the extractor and start pumping the output feature events to
+// the registered callback. Note that this method will create one or more
+// threads to handle feature processing.
+//
+// @param extractor The DvrTrackingFeatureExtractor to destroy.
+int dvrTrackingFeatureExtractorStart(DvrTrackingFeatureExtractor* extractor,
+                                     DvrTrackingFeatureCallback callback,
+                                     void* context);
+
+// Stops the tracking feature extractor.
+//
+// This will stop the extractor session and clean up all internal resourcse
+// related to this extractor. On succssful return, all internal therad started
+// by dvrTrackingFeatureExtractorStart should be stopped.
+//
+// @param extractor The DvrTrackingFeatureExtractor to destroy.
+int dvrTrackingFeatureExtractorStop(DvrTrackingFeatureExtractor* extractor);
+
+// Processes one buffer to extract features from.
+//
+// The buffer will be sent over to DSP for feature extraction. Once the process
+// is done, the processing thread will invoke DvrTrackingFeatureCallback with
+// newly extracted features. Note that not all buffers will be processed, as the
+// underlying DSP can only process buffers at a certain framerate. If a buffer
+// needs to be skipped, out_skipped filed will be set to true. Also note that
+// for successfully processed stereo buffer, two callbacks (one for each eye)
+// will be fired.
+//
+// @param extractor The DvrTrackingFeatureExtractor to destroy.
+// @param buffer The buffer to extract features from. Note that the buffer must
+//     be in acquired state for the buffer to be processed. Also note that the
+//     buffer will be released back to its producer on successful return of the
+//     method.
+// @param metadata The metadata associated with the buffer. Should be populated
+//     by DvrTrackingCamera session as user defined metadata.
+// @param out_skipped On successful return, the field will be set to true iff
+//     the buffer was skipped; and false iff the buffer was processed. This
+//     field is optional and nullptr can be passed here to ignore the field.
+// @return Zero on success, or negative error code.
+int dvrTrackingFeatureExtractorProcessBuffer(
+    DvrTrackingFeatureExtractor* extractor, DvrReadBuffer* buffer,
+    const DvrTrackingBufferMetadata* metadata, bool* out_skipped);
+
+__END_DECLS
+
+#endif  // ANDROID_DVR_TRACKING_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_tracking_types.h b/libs/vr/libdvr/include/dvr/dvr_tracking_types.h
new file mode 100644
index 0000000..81310d2
--- /dev/null
+++ b/libs/vr/libdvr/include/dvr/dvr_tracking_types.h
@@ -0,0 +1,104 @@
+#ifndef ANDROID_DVR_TRACKING_TYPES_H_
+#define ANDROID_DVR_TRACKING_TYPES_H_
+
+#include <stdint.h>
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+
+typedef struct DvrTrackingBufferMetadata {
+  // Specifies the source of this image.
+  uint32_t camera_mask;
+  // Specifies the memory format of this image.
+  uint32_t format;
+  /// The width of the image data.
+  uint32_t width;
+  /// The height of the image data.
+  uint32_t height;
+  /// The number of bytes per scanline of image data.
+  uint32_t stride;
+  /// The frame number of this image.
+  int32_t frame_number;
+  /// The timestamp of this image in nanoseconds. Taken in the middle of the
+  /// exposure interval.
+  int64_t timestamp_ns;
+  // This is the timestamp for recording when the system using the HAL
+  // received the callback.  It will not be populated by the HAL.
+  int64_t callback_timestamp_ns;
+  /// The exposure duration of this image in nanoseconds.
+  int64_t exposure_duration_ns;
+} DvrTrackingBufferMetadata;
+
+// Represents a set of features extracted from a camera frame. Note that this
+// should be in sync with TangoHalCallbacks defined in tango-hal.h.
+typedef struct DvrTrackingFeatures {
+  // Specifies the source of the features.
+  uint32_t camera_mask;
+
+  // This is unused.
+  uint32_t unused;
+
+  // The timestamp in nanoseconds from the image that generated the features.
+  // Taken in the middle of the exposure interval.
+  int64_t timestamp_ns;
+
+  // This is the timestamp for recording when the system using the HAL
+  // received the callback.  It will not be populated by the HAL.
+  int64_t callback_timestamp_ns;
+
+  // The frame number from the image that generated the features.
+  int64_t frame_number;
+
+  // The number of features.
+  int count;
+
+  // An array of 2D image points for each feature in the current image.
+  // This is sub-pixel refined extremum location at the fine resolution.
+  float (*positions)[2];
+
+  // The id of these measurements.
+  int32_t* ids;
+
+  // The feature descriptors.
+  uint64_t (*descriptors)[8];
+
+  // Laplacian scores for each feature.
+  float* scores;
+
+  // Is this feature a minimum or maximum in the Laplacian image.
+  // 0 if the feature is a maximum, 1 if it is a minimum.
+  int32_t* is_minimum;
+
+  // This corresponds to the sub-pixel index of the laplacian image
+  // that the extremum was found.
+  float* scales;
+
+  // Computed orientation of keypoint as part of FREAK extraction, except
+  // it's represented in radians and measured anti-clockwise.
+  float* angles;
+
+  // Edge scores for each feature.
+  float* edge_scores;
+} DvrTrackingFeatures;
+
+// Represents a sensor event.
+typedef struct DvrTrackingSensorEvent {
+  // The sensor type.
+  int32_t sensor;
+
+  // Event type.
+  int32_t type;
+
+  // This is the timestamp recorded from the device. Taken in the middle
+  // of the integration interval and adjusted for any low pass filtering.
+  int64_t timestamp_ns;
+
+  // The event data.
+  float x;
+  float y;
+  float z;
+} DvrTrackingSensorEvent;
+
+__END_DECLS
+
+#endif  // ANDROID_DVR_TRACKING_TYPES_H_
diff --git a/libs/vr/libdvr/include/dvr/dvr_vsync.h b/libs/vr/libdvr/include/dvr/dvr_vsync.h
index 87fdf31..498bb5c 100644
--- a/libs/vr/libdvr/include/dvr/dvr_vsync.h
+++ b/libs/vr/libdvr/include/dvr/dvr_vsync.h
@@ -6,8 +6,6 @@
 
 __BEGIN_DECLS
 
-typedef struct DvrVSyncClient DvrVSyncClient;
-
 // Represents a vsync sample. The size of this struct is 32 bytes.
 typedef struct __attribute__((packed, aligned(16))) DvrVsync {
   // The timestamp for the last vsync in nanoseconds.
@@ -29,19 +27,6 @@
   uint8_t padding[8];
 } DvrVsync;
 
-// Creates a new client to the system vsync service.
-int dvrVSyncClientCreate(DvrVSyncClient** client_out);
-
-// Destroys the vsync client.
-void dvrVSyncClientDestroy(DvrVSyncClient* client);
-
-// Get the estimated timestamp of the next GPU lens warp preemption event in/
-// ns. Also returns the corresponding vsync count that the next lens warp
-// operation will target.
-int dvrVSyncClientGetSchedInfo(DvrVSyncClient* client, int64_t* vsync_period_ns,
-                               int64_t* next_timestamp_ns,
-                               uint32_t* next_vsync_count);
-
 __END_DECLS
 
 #endif  // ANDROID_DVR_VSYNC_H_
diff --git a/libs/vr/libdvr/tests/Android.bp b/libs/vr/libdvr/tests/Android.bp
index 1ae75fb..b23a0fa 100644
--- a/libs/vr/libdvr/tests/Android.bp
+++ b/libs/vr/libdvr/tests/Android.bp
@@ -12,38 +12,36 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-shared_libraries = [
-    "libbase",
-    "libbinder",
-    "libbufferhubqueue",
-    "libcutils",
-    "libgui",
-    "liblog",
-    "libhardware",
-    "libui",
-    "libutils",
-    "libnativewindow",
-    "libpdx_default_transport",
-]
-
-static_libraries = [
-    "libdvr_static",
-    "libchrome",
-    "libdvrcommon",
-    "libdisplay",
-    "libbroadcastring",
-]
-
 cc_test {
     srcs: [
         "dvr_display_manager-test.cpp",
         "dvr_named_buffer-test.cpp",
+        "dvr_tracking-test.cpp",
     ],
 
     header_libs: ["libdvr_headers"],
-    static_libs: static_libraries,
-    shared_libs: shared_libraries,
+    static_libs: [
+        "libdvr_static",
+        "libchrome",
+        "libdvrcommon",
+        "libdisplay",
+        "libbroadcastring",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libbufferhubqueue",
+        "libcutils",
+        "libgui",
+        "liblog",
+        "libhardware",
+        "libui",
+        "libutils",
+        "libnativewindow",
+        "libpdx_default_transport",
+    ],
     cflags: [
+        "-DDVR_TRACKING_IMPLEMENTED=0",
         "-DLOG_TAG=\"dvr_api-test\"",
         "-DTRACE=0",
         "-Wno-missing-field-initializers",
@@ -52,3 +50,55 @@
     ],
     name: "dvr_api-test",
 }
+
+cc_test {
+    name: "dvr_buffer_queue-test",
+
+    // Includes the dvr_api.h header. Tests should only include "dvr_api.h",
+    // and shall only get access to |dvrGetApi|, as other symbols are hidden
+    // from the library.
+    include_dirs: ["frameworks/native/libs/vr/libdvr/include"],
+
+    srcs: ["dvr_buffer_queue-test.cpp"],
+
+    shared_libs: [
+        "libandroid",
+        "liblog",
+    ],
+
+    cflags: [
+        "-DTRACE=0",
+        "-O2",
+        "-g",
+    ],
+
+    // DTS Should only link to NDK libraries.
+    sdk_version: "26",
+    stl: "c++_static",
+}
+
+cc_test {
+    name: "dvr_display-test",
+
+    include_dirs: [
+        "frameworks/native/libs/vr/libdvr/include",
+        "frameworks/native/libs/nativewindow/include",
+    ],
+
+    srcs: ["dvr_display-test.cpp"],
+
+    shared_libs: [
+        "libandroid",
+        "liblog",
+    ],
+
+    cflags: [
+        "-DTRACE=0",
+        "-O2",
+        "-g",
+    ],
+
+    // DTS Should only link to NDK libraries.
+    sdk_version: "26",
+    stl: "c++_static",
+}
diff --git a/libs/vr/libdvr/tests/Android.mk b/libs/vr/libdvr/tests/Android.mk
deleted file mode 100644
index 0f3840d..0000000
--- a/libs/vr/libdvr/tests/Android.mk
+++ /dev/null
@@ -1,73 +0,0 @@
-# Copyright (C) 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.
-
-LOCAL_PATH:= $(call my-dir)
-
-# TODO(b/73133405): Currently, building cc_test against NDK using Android.bp
-# doesn't work well. Migrate to use Android.bp once b/73133405 gets fixed.
-
-include $(CLEAR_VARS)
-LOCAL_MODULE:= dvr_buffer_queue-test
-
-# Includes the dvr_api.h header. Tests should only include "dvr_api.h",
-# and shall only get access to |dvrGetApi|, as other symbols are hidden from the
-# library.
-LOCAL_C_INCLUDES := \
-    frameworks/native/libs/vr/libdvr/include \
-
-LOCAL_SANITIZE := thread
-
-LOCAL_SRC_FILES := dvr_buffer_queue-test.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libandroid \
-    liblog \
-
-LOCAL_CFLAGS := \
-    -DTRACE=0 \
-    -O2 \
-    -g \
-
-# DTS Should only link to NDK libraries.
-LOCAL_SDK_VERSION := 26
-LOCAL_NDK_STL_VARIANT := c++_static
-
-include $(BUILD_NATIVE_TEST)
-
-
-include $(CLEAR_VARS)
-LOCAL_MODULE:= dvr_display-test
-
-LOCAL_C_INCLUDES := \
-    frameworks/native/libs/vr/libdvr/include \
-    frameworks/native/libs/nativewindow/include
-
-LOCAL_SANITIZE := thread
-
-LOCAL_SRC_FILES := dvr_display-test.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-    libandroid \
-    liblog
-
-LOCAL_CFLAGS := \
-    -DTRACE=0 \
-    -O2 \
-    -g
-
-# DTS Should only link to NDK libraries.
-LOCAL_SDK_VERSION := 26
-LOCAL_NDK_STL_VARIANT := c++_static
-
-include $(BUILD_NATIVE_TEST)
\ No newline at end of file
diff --git a/libs/vr/libdvr/tests/dvr_tracking-test.cpp b/libs/vr/libdvr/tests/dvr_tracking-test.cpp
new file mode 100644
index 0000000..3b6d6e1
--- /dev/null
+++ b/libs/vr/libdvr/tests/dvr_tracking-test.cpp
@@ -0,0 +1,103 @@
+#include <android/log.h>
+#include <gtest/gtest.h>
+
+#include "dvr_api_test.h"
+
+namespace {
+
+class DvrTrackingTest : public DvrApiTest {};
+
+#if DVR_TRACKING_IMPLEMENTED
+
+TEST_F(DvrTrackingTest, Implemented) {
+  ASSERT_TRUE(api_.TrackingCameraCreate != nullptr);
+  ASSERT_TRUE(api_.TrackingCameraStart != nullptr);
+  ASSERT_TRUE(api_.TrackingCameraStop != nullptr);
+
+  ASSERT_TRUE(api_.TrackingFeatureExtractorCreate != nullptr);
+  ASSERT_TRUE(api_.TrackingFeatureExtractorDestroy != nullptr);
+  ASSERT_TRUE(api_.TrackingFeatureExtractorStart != nullptr);
+  ASSERT_TRUE(api_.TrackingFeatureExtractorStop != nullptr);
+  ASSERT_TRUE(api_.TrackingFeatureExtractorProcessBuffer != nullptr);
+}
+
+TEST_F(DvrTrackingTest, CameraCreateFailsForInvalidInput) {
+  int ret;
+  ret = api_.TrackingCameraCreate(nullptr);
+  EXPECT_EQ(ret, -EINVAL);
+
+  DvrTrackingCamera* camera = reinterpret_cast<DvrTrackingCamera*>(42);
+  ret = api_.TrackingCameraCreate(&camera);
+  EXPECT_EQ(ret, -EINVAL);
+}
+
+TEST_F(DvrTrackingTest, CameraCreateDestroy) {
+  DvrTrackingCamera* camera = nullptr;
+  int ret = api_.TrackingCameraCreate(&camera);
+
+  EXPECT_EQ(ret, 0);
+  ASSERT_TRUE(camera != nullptr);
+
+  api_.TrackingCameraDestroy(camera);
+}
+
+TEST_F(DvrTrackingTest, FeatureExtractorCreateFailsForInvalidInput) {
+  int ret;
+  ret = api_.TrackingFeatureExtractorCreate(nullptr);
+  EXPECT_EQ(ret, -EINVAL);
+
+  DvrTrackingFeatureExtractor* camera =
+      reinterpret_cast<DvrTrackingFeatureExtractor*>(42);
+  ret = api_.TrackingFeatureExtractorCreate(&camera);
+  EXPECT_EQ(ret, -EINVAL);
+}
+
+TEST_F(DvrTrackingTest, FeatureExtractorCreateDestroy) {
+  DvrTrackingFeatureExtractor* camera = nullptr;
+  int ret = api_.TrackingFeatureExtractorCreate(&camera);
+
+  EXPECT_EQ(ret, 0);
+  ASSERT_TRUE(camera != nullptr);
+
+  api_.TrackingFeatureExtractorDestroy(camera);
+}
+
+#else  // !DVR_TRACKING_IMPLEMENTED
+
+TEST_F(DvrTrackingTest, NotImplemented) {
+  ASSERT_TRUE(api_.TrackingCameraCreate != nullptr);
+  ASSERT_TRUE(api_.TrackingCameraDestroy != nullptr);
+  ASSERT_TRUE(api_.TrackingCameraStart != nullptr);
+  ASSERT_TRUE(api_.TrackingCameraStop != nullptr);
+
+  EXPECT_EQ(api_.TrackingCameraCreate(nullptr), -ENOSYS);
+  EXPECT_EQ(api_.TrackingCameraStart(nullptr, nullptr), -ENOSYS);
+  EXPECT_EQ(api_.TrackingCameraStop(nullptr), -ENOSYS);
+
+  ASSERT_TRUE(api_.TrackingFeatureExtractorCreate != nullptr);
+  ASSERT_TRUE(api_.TrackingFeatureExtractorDestroy != nullptr);
+  ASSERT_TRUE(api_.TrackingFeatureExtractorStart != nullptr);
+  ASSERT_TRUE(api_.TrackingFeatureExtractorStop != nullptr);
+  ASSERT_TRUE(api_.TrackingFeatureExtractorProcessBuffer != nullptr);
+
+  EXPECT_EQ(api_.TrackingFeatureExtractorCreate(nullptr), -ENOSYS);
+  EXPECT_EQ(api_.TrackingFeatureExtractorStart(nullptr, nullptr, nullptr),
+            -ENOSYS);
+  EXPECT_EQ(api_.TrackingFeatureExtractorStop(nullptr), -ENOSYS);
+  EXPECT_EQ(api_.TrackingFeatureExtractorProcessBuffer(nullptr, nullptr,
+                                                       nullptr, nullptr),
+            -ENOSYS);
+
+  ASSERT_TRUE(api_.TrackingSensorsCreate != nullptr);
+  ASSERT_TRUE(api_.TrackingSensorsDestroy != nullptr);
+  ASSERT_TRUE(api_.TrackingSensorsStart != nullptr);
+  ASSERT_TRUE(api_.TrackingSensorsStop != nullptr);
+
+  EXPECT_EQ(api_.TrackingSensorsCreate(nullptr, nullptr), -ENOSYS);
+  EXPECT_EQ(api_.TrackingSensorsStart(nullptr, nullptr, nullptr), -ENOSYS);
+  EXPECT_EQ(api_.TrackingSensorsStop(nullptr), -ENOSYS);
+}
+
+#endif  // DVR_TRACKING_IMPLEMENTED
+
+}  // namespace
diff --git a/libs/vr/libpdx/private/pdx/service.h b/libs/vr/libpdx/private/pdx/service.h
index 13aa3e9..15fa327 100644
--- a/libs/vr/libpdx/private/pdx/service.h
+++ b/libs/vr/libpdx/private/pdx/service.h
@@ -59,9 +59,18 @@
   virtual ~Channel() {}
 
   /*
+   * Accessors to the pid of the last active client.
+   */
+  pid_t GetActiveProcessId() const { return client_pid_; }
+  void SetActiveProcessId(pid_t pid) { client_pid_ = pid; }
+
+  /*
    * Utility to get a shared_ptr reference from the channel context pointer.
    */
   static std::shared_ptr<Channel> GetFromMessageInfo(const MessageInfo& info);
+
+ private:
+  pid_t client_pid_ = 0;
 };
 
 /*
diff --git a/libs/vr/libpdx_uds/service_endpoint.cpp b/libs/vr/libpdx_uds/service_endpoint.cpp
index 32d40e8..ecbfdba 100644
--- a/libs/vr/libpdx_uds/service_endpoint.cpp
+++ b/libs/vr/libpdx_uds/service_endpoint.cpp
@@ -521,6 +521,9 @@
   info.flags = 0;
   info.service = service_;
   info.channel = GetChannelState(channel_id);
+  if (info.channel != nullptr) {
+    info.channel->SetActiveProcessId(request.cred.pid);
+  }
   info.send_len = request.send_len;
   info.recv_len = request.max_recv_len;
   info.fd_count = request.file_descriptors.size();
diff --git a/libs/vr/libvrflinger/Android.bp b/libs/vr/libvrflinger/Android.bp
index 4dc669b..776dd8e 100644
--- a/libs/vr/libvrflinger/Android.bp
+++ b/libs/vr/libvrflinger/Android.bp
@@ -20,7 +20,6 @@
     "display_surface.cpp",
     "hardware_composer.cpp",
     "vr_flinger.cpp",
-    "vsync_service.cpp",
 ]
 
 includeFiles = [ "include" ]
@@ -40,6 +39,7 @@
     "android.hardware.graphics.allocator@2.0",
     "android.hardware.graphics.composer@2.1",
     "android.hardware.graphics.composer@2.2",
+    "android.hardware.graphics.composer@2.3",
     "libbinder",
     "libbase",
     "libbufferhubqueue",
@@ -92,3 +92,7 @@
     header_libs: headerLibraries,
     name: "libvrflinger",
 }
+
+subdirs = [
+    "tests",
+]
diff --git a/libs/vr/libvrflinger/display_service.h b/libs/vr/libvrflinger/display_service.h
index 3090bd1..6fad58e 100644
--- a/libs/vr/libvrflinger/display_service.h
+++ b/libs/vr/libvrflinger/display_service.h
@@ -60,11 +60,6 @@
   void SetDisplayConfigurationUpdateNotifier(
       DisplayConfigurationUpdateNotifier notifier);
 
-  using VSyncCallback = HardwareComposer::VSyncCallback;
-  void SetVSyncCallback(VSyncCallback callback) {
-    hardware_composer_.SetVSyncCallback(callback);
-  }
-
   void GrantDisplayOwnership() { hardware_composer_.Enable(); }
   void SeizeDisplayOwnership() { hardware_composer_.Disable(); }
   void OnBootFinished() { hardware_composer_.OnBootFinished(); }
diff --git a/libs/vr/libvrflinger/hardware_composer.cpp b/libs/vr/libvrflinger/hardware_composer.cpp
index 44ce78c..e98d592 100644
--- a/libs/vr/libvrflinger/hardware_composer.cpp
+++ b/libs/vr/libvrflinger/hardware_composer.cpp
@@ -1,5 +1,6 @@
 #include "hardware_composer.h"
 
+#include <binder/IServiceManager.h>
 #include <cutils/properties.h>
 #include <cutils/sched_policy.h>
 #include <fcntl.h>
@@ -52,6 +53,10 @@
 
 const char kUseExternalDisplayProperty[] = "persist.vr.use_external_display";
 
+// Surface flinger uses "VSYNC-sf" and "VSYNC-app" for its version of these
+// events. Name ours similarly.
+const char kVsyncTraceEventName[] = "VSYNC-vrflinger";
+
 // How long to wait after boot finishes before we turn the display off.
 constexpr int kBootFinishedDisplayOffTimeoutSec = 10;
 
@@ -131,6 +136,7 @@
   UpdatePostThreadState(PostThreadState::Quit, true);
   if (post_thread_.joinable())
     post_thread_.join();
+  composer_callback_->SetVsyncService(nullptr);
 }
 
 bool HardwareComposer::Initialize(
@@ -147,6 +153,13 @@
 
   primary_display_ = GetDisplayParams(composer, primary_display_id, true);
 
+  vsync_service_ = new VsyncService;
+  sp<IServiceManager> sm(defaultServiceManager());
+  auto result = sm->addService(String16(VsyncService::GetServiceName()),
+      vsync_service_, false);
+  LOG_ALWAYS_FATAL_IF(result != android::OK,
+      "addService(%s) failed", VsyncService::GetServiceName());
+
   post_thread_event_fd_.Reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
   LOG_ALWAYS_FATAL_IF(
       !post_thread_event_fd_,
@@ -223,6 +236,7 @@
   LOG_ALWAYS_FATAL_IF(!composer_callback_->GotFirstHotplug(),
       "Registered composer callback but didn't get hotplug for primary"
       " display");
+  composer_callback_->SetVsyncService(vsync_service_);
 }
 
 void HardwareComposer::OnPostThreadResumed() {
@@ -242,7 +256,10 @@
   // Standalones only create the composer client once and then use SetPowerMode
   // to control the screen on pause/resume.
   if (!is_standalone_device_) {
-    composer_callback_ = nullptr;
+    if (composer_callback_ != nullptr) {
+      composer_callback_->SetVsyncService(nullptr);
+      composer_callback_ = nullptr;
+    }
     composer_.reset(nullptr);
   } else {
     EnableDisplay(*target_display_, false);
@@ -336,7 +353,6 @@
   // According to the documentation, this fence is signaled at the time of
   // vsync/DMA for physical displays.
   if (error == HWC::Error::None) {
-    ATRACE_INT("HardwareComposer: VsyncFence", present_fence);
     retire_fence_fds_.emplace_back(present_fence);
   } else {
     ATRACE_INT("HardwareComposer: PresentResult", error);
@@ -775,6 +791,11 @@
       std::unique_lock<std::mutex> lock(post_thread_mutex_);
       ALOGI("HardwareComposer::PostThread: Entering quiescent state.");
 
+      if (was_running) {
+        vsync_trace_parity_ = false;
+        ATRACE_INT(kVsyncTraceEventName, 0);
+      }
+
       // Tear down resources.
       OnPostThreadPaused();
       was_running = false;
@@ -848,6 +869,9 @@
       vsync_timestamp = status.get();
     }
 
+    vsync_trace_parity_ = !vsync_trace_parity_;
+    ATRACE_INT(kVsyncTraceEventName, vsync_trace_parity_ ? 1 : 0);
+
     // Advance the vsync counter only if the system is keeping up with hardware
     // vsync to give clients an indication of the delays.
     if (vsync_prediction_interval_ == 1)
@@ -867,11 +891,6 @@
       vsync_ring_->Publish(vsync);
     }
 
-    // Signal all of the vsync clients. Because absolute time is used for the
-    // wakeup time below, this can take a little time if necessary.
-    if (vsync_callback_)
-      vsync_callback_(vsync_timestamp, /*frame_time_estimate*/ 0, vsync_count_);
-
     {
       // Sleep until shortly before vsync.
       ATRACE_NAME("sleep");
@@ -1063,8 +1082,45 @@
            layers_.size());
 }
 
-void HardwareComposer::SetVSyncCallback(VSyncCallback callback) {
-  vsync_callback_ = callback;
+std::vector<sp<IVsyncCallback>>::const_iterator
+HardwareComposer::VsyncService::FindCallback(
+    const sp<IVsyncCallback>& callback) const {
+  sp<IBinder> binder = IInterface::asBinder(callback);
+  return std::find_if(callbacks_.cbegin(), callbacks_.cend(),
+                      [&](const sp<IVsyncCallback>& callback) {
+                        return IInterface::asBinder(callback) == binder;
+                      });
+}
+
+status_t HardwareComposer::VsyncService::registerCallback(
+    const sp<IVsyncCallback> callback) {
+  std::lock_guard<std::mutex> autolock(mutex_);
+  if (FindCallback(callback) == callbacks_.cend()) {
+    callbacks_.push_back(callback);
+  }
+  return NO_ERROR;
+}
+
+status_t HardwareComposer::VsyncService::unregisterCallback(
+    const sp<IVsyncCallback> callback) {
+  std::lock_guard<std::mutex> autolock(mutex_);
+  auto iter = FindCallback(callback);
+  if (iter != callbacks_.cend()) {
+    callbacks_.erase(iter);
+  }
+  return NO_ERROR;
+}
+
+void HardwareComposer::VsyncService::OnVsync(int64_t vsync_timestamp) {
+  ATRACE_NAME("VsyncService::OnVsync");
+  std::lock_guard<std::mutex> autolock(mutex_);
+  for (auto iter = callbacks_.begin(); iter != callbacks_.end();) {
+    if ((*iter)->onVsync(vsync_timestamp) == android::DEAD_OBJECT) {
+      iter = callbacks_.erase(iter);
+    } else {
+      ++iter;
+    }
+  }
 }
 
 Return<void> HardwareComposer::ComposerCallback::onHotplug(
@@ -1123,16 +1179,26 @@
 
 Return<void> HardwareComposer::ComposerCallback::onVsync(Hwc2::Display display,
                                                          int64_t timestamp) {
+  TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|",
+               display, timestamp);
+  std::lock_guard<std::mutex> lock(mutex_);
   DisplayInfo* display_info = GetDisplayInfo(display);
   if (display_info) {
-    TRACE_FORMAT("vsync_callback|display=%" PRIu64 ";timestamp=%" PRId64 "|",
-                 display, timestamp);
     display_info->callback_vsync_timestamp = timestamp;
   }
+  if (primary_display_.id == display && vsync_service_ != nullptr) {
+    vsync_service_->OnVsync(timestamp);
+  }
 
   return Void();
 }
 
+void HardwareComposer::ComposerCallback::SetVsyncService(
+    const sp<VsyncService>& vsync_service) {
+  std::lock_guard<std::mutex> lock(mutex_);
+  vsync_service_ = vsync_service;
+}
+
 HardwareComposer::ComposerCallback::Displays
 HardwareComposer::ComposerCallback::GetDisplays() {
   std::lock_guard<std::mutex> lock(mutex_);
@@ -1149,6 +1215,7 @@
 
 Status<int64_t> HardwareComposer::ComposerCallback::GetVsyncTime(
     hwc2_display_t display) {
+  std::lock_guard<std::mutex> autolock(mutex_);
   DisplayInfo* display_info = GetDisplayInfo(display);
   if (!display_info) {
     ALOGW("Attempt to get vsync time for unknown display %" PRIu64, display);
@@ -1160,7 +1227,6 @@
   if (!event_fd) {
     // Fall back to returning the last timestamp returned by the vsync
     // callback.
-    std::lock_guard<std::mutex> autolock(mutex_);
     return display_info->callback_vsync_timestamp;
   }
 
diff --git a/libs/vr/libvrflinger/hardware_composer.h b/libs/vr/libvrflinger/hardware_composer.h
index 1d8d463..80fa7ac 100644
--- a/libs/vr/libvrflinger/hardware_composer.h
+++ b/libs/vr/libvrflinger/hardware_composer.h
@@ -24,6 +24,7 @@
 #include <pdx/rpc/variant.h>
 #include <private/dvr/buffer_hub_client.h>
 #include <private/dvr/shared_buffer_helpers.h>
+#include <private/dvr/vsync_service.h>
 
 #include "acquired_buffer.h"
 #include "display_surface.h"
@@ -300,8 +301,6 @@
 // will access the state and whether it needs to be synchronized.
 class HardwareComposer {
  public:
-  // Type for vsync callback.
-  using VSyncCallback = std::function<void(int64_t, int64_t, uint32_t)>;
   using RequestDisplayCallback = std::function<void(bool)>;
 
   HardwareComposer();
@@ -325,8 +324,6 @@
 
   std::string Dump();
 
-  void SetVSyncCallback(VSyncCallback callback);
-
   const DisplayParams& GetPrimaryDisplayParams() const {
     return primary_display_;
   }
@@ -350,6 +347,18 @@
   // on/off. Returns true on success, false on failure.
   bool EnableDisplay(const DisplayParams& display, bool enabled);
 
+  class VsyncService : public BnVsyncService {
+   public:
+    status_t registerCallback(const sp<IVsyncCallback> callback) override;
+    status_t unregisterCallback(const sp<IVsyncCallback> callback) override;
+    void OnVsync(int64_t vsync_timestamp);
+   private:
+    std::vector<sp<IVsyncCallback>>::const_iterator FindCallback(
+        const sp<IVsyncCallback>& callback) const;
+    std::mutex mutex_;
+    std::vector<sp<IVsyncCallback>> callbacks_;
+  };
+
   class ComposerCallback : public Hwc2::IComposerCallback {
    public:
     ComposerCallback() = default;
@@ -360,6 +369,7 @@
                                    int64_t timestamp) override;
 
     bool GotFirstHotplug() { return got_first_hotplug_; }
+    void SetVsyncService(const sp<VsyncService>& vsync_service);
 
     struct Displays {
       hwc2_display_t primary_display = 0;
@@ -385,6 +395,7 @@
     DisplayInfo primary_display_;
     std::optional<DisplayInfo> external_display_;
     bool external_display_was_hotplugged_ = false;
+    sp<VsyncService> vsync_service_;
   };
 
   HWC::Error Validate(hwc2_display_t display);
@@ -484,9 +495,6 @@
   // vector must be sorted by surface_id in ascending order.
   std::vector<Layer> layers_;
 
-  // Handler to hook vsync events outside of this class.
-  VSyncCallback vsync_callback_;
-
   // The layer posting thread. This thread wakes up a short time before vsync to
   // hand buffers to hardware composer.
   std::thread post_thread_;
@@ -534,6 +542,9 @@
   DvrConfig post_thread_config_;
   std::mutex shared_config_mutex_;
 
+  bool vsync_trace_parity_ = false;
+  sp<VsyncService> vsync_service_;
+
   static constexpr int kPostThreadInterrupted = 1;
 
   HardwareComposer(const HardwareComposer&) = delete;
diff --git a/libs/vr/libvrflinger/tests/Android.bp b/libs/vr/libvrflinger/tests/Android.bp
new file mode 100644
index 0000000..d500278
--- /dev/null
+++ b/libs/vr/libvrflinger/tests/Android.bp
@@ -0,0 +1,37 @@
+shared_libs = [
+    "android.hardware.configstore-utils",
+    "android.hardware.configstore@1.0",
+    "libbinder",
+    "libbufferhubqueue",
+    "libcutils",
+    "libgui",
+    "libhidlbase",
+    "liblog",
+    "libui",
+    "libutils",
+    "libnativewindow",
+    "libpdx_default_transport",
+]
+
+static_libs = [
+    "libdisplay",
+]
+
+cc_test {
+    srcs: ["vrflinger_test.cpp"],
+    // See go/apct-presubmit for documentation on how this .filter file is used
+    // by Android's automated testing infrastructure for test filtering.
+    data: ["vrflinger_test.filter"],
+    static_libs: static_libs,
+    shared_libs: shared_libs,
+    cflags: [
+        "-DLOG_TAG=\"VrFlingerTest\"",
+        "-DTRACE=0",
+        "-O0",
+        "-g",
+        "-Wall",
+        "-Werror",
+    ],
+    cppflags: ["-std=c++1z"],
+    name: "vrflinger_test",
+}
diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.cpp b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
new file mode 100644
index 0000000..e1c7adb
--- /dev/null
+++ b/libs/vr/libvrflinger/tests/vrflinger_test.cpp
@@ -0,0 +1,264 @@
+#include <android/hardware/configstore/1.0/ISurfaceFlingerConfigs.h>
+#include <android/hardware/configstore/1.1/types.h>
+#include <android/hardware_buffer.h>
+#include <binder/IServiceManager.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <configstore/Utils.h>
+#include <cutils/properties.h>
+#include <gtest/gtest.h>
+#include <gui/ISurfaceComposer.h>
+#include <log/log.h>
+#include <utils/StrongPointer.h>
+
+#include <chrono>
+#include <memory>
+#include <mutex>
+#include <optional>
+#include <thread>
+
+#include <private/dvr/display_client.h>
+
+using namespace android::hardware::configstore;
+using namespace android::hardware::configstore::V1_0;
+using android::dvr::display::DisplayClient;
+using android::dvr::display::Surface;
+using android::dvr::display::SurfaceAttribute;
+using android::dvr::display::SurfaceAttributeValue;
+
+namespace android {
+namespace dvr {
+
+// The transaction code for asking surface flinger if vr flinger is active. This
+// is done as a hidden api since it's only used for tests. See the "case 1028"
+// block in SurfaceFlinger::onTransact() in SurfaceFlinger.cpp.
+constexpr uint32_t kIsVrFlingerActiveTransactionCode = 1028;
+
+// The maximum amount of time to give vr flinger to activate/deactivate. If the
+// switch hasn't completed in this amount of time, the test will fail.
+constexpr auto kVrFlingerSwitchMaxTime = std::chrono::seconds(1);
+
+// How long to wait between each check to see if the vr flinger switch
+// completed.
+constexpr auto kVrFlingerSwitchPollInterval = std::chrono::milliseconds(50);
+
+// How long to wait for a device that boots to VR to have vr flinger ready.
+constexpr auto kBootVrFlingerWaitTimeout = std::chrono::seconds(30);
+
+// A Binder connection to surface flinger.
+class SurfaceFlingerConnection {
+ public:
+  static std::unique_ptr<SurfaceFlingerConnection> Create() {
+    sp<ISurfaceComposer> surface_flinger = interface_cast<ISurfaceComposer>(
+        defaultServiceManager()->getService(String16("SurfaceFlinger")));
+    if (surface_flinger == nullptr) {
+      return nullptr;
+    }
+
+    return std::unique_ptr<SurfaceFlingerConnection>(
+        new SurfaceFlingerConnection(surface_flinger));
+  }
+
+  // Returns true if the surface flinger process is still running. We use this
+  // to detect if surface flinger has crashed.
+  bool IsAlive() {
+    IInterface::asBinder(surface_flinger_)->pingBinder();
+    return IInterface::asBinder(surface_flinger_)->isBinderAlive();
+  }
+
+  // Return true if vr flinger is currently active, false otherwise. If there's
+  // an error communicating with surface flinger, std::nullopt is returned.
+  std::optional<bool> IsVrFlingerActive() {
+    Parcel data, reply;
+    status_t result =
+        data.writeInterfaceToken(surface_flinger_->getInterfaceDescriptor());
+    if (result != NO_ERROR) {
+      return std::nullopt;
+    }
+    result = IInterface::asBinder(surface_flinger_)
+                 ->transact(kIsVrFlingerActiveTransactionCode, data, &reply);
+    if (result != NO_ERROR) {
+      return std::nullopt;
+    }
+    bool vr_flinger_active;
+    result = reply.readBool(&vr_flinger_active);
+    if (result != NO_ERROR) {
+      return std::nullopt;
+    }
+    return vr_flinger_active;
+  }
+
+  enum class VrFlingerSwitchResult : int8_t {
+    kSuccess,
+    kTimedOut,
+    kCommunicationError,
+    kSurfaceFlingerDied
+  };
+
+  // Wait for vr flinger to become active or inactive.
+  VrFlingerSwitchResult WaitForVrFlinger(bool wait_active) {
+    return WaitForVrFlingerTimed(wait_active, kVrFlingerSwitchPollInterval,
+        kVrFlingerSwitchMaxTime);
+  }
+
+  // Wait for vr flinger to become active or inactive, specifying custom timeouts.
+  VrFlingerSwitchResult WaitForVrFlingerTimed(bool wait_active,
+      std::chrono::milliseconds pollInterval, std::chrono::seconds timeout) {
+    auto start_time = std::chrono::steady_clock::now();
+    while (1) {
+      std::this_thread::sleep_for(pollInterval);
+      if (!IsAlive()) {
+        return VrFlingerSwitchResult::kSurfaceFlingerDied;
+      }
+      std::optional<bool> vr_flinger_active = IsVrFlingerActive();
+      if (!vr_flinger_active.has_value()) {
+        return VrFlingerSwitchResult::kCommunicationError;
+      }
+      if (vr_flinger_active.value() == wait_active) {
+        return VrFlingerSwitchResult::kSuccess;
+      } else if (std::chrono::steady_clock::now() - start_time > timeout) {
+        return VrFlingerSwitchResult::kTimedOut;
+      }
+    }
+  }
+
+ private:
+  SurfaceFlingerConnection(sp<ISurfaceComposer> surface_flinger)
+      : surface_flinger_(surface_flinger) {}
+
+  sp<ISurfaceComposer> surface_flinger_ = nullptr;
+};
+
+// This test activates vr flinger by creating a vr flinger surface, then
+// deactivates vr flinger by destroying the surface. We verify that vr flinger
+// is activated and deactivated as expected, and that surface flinger doesn't
+// crash.
+//
+// If the device doesn't support vr flinger (as repoted by ConfigStore), the
+// test does nothing.
+//
+// If the device is a standalone vr device, the test also does nothing, since
+// this test verifies the behavior of display handoff from surface flinger to vr
+// flinger and back, and standalone devices never hand control of the display
+// back to surface flinger.
+TEST(VrFlingerTest, ActivateDeactivate) {
+  android::ProcessState::self()->startThreadPool();
+
+  // Exit immediately if the device doesn't support vr flinger. This ConfigStore
+  // check is the same mechanism used by surface flinger to decide if it should
+  // initialize vr flinger.
+  bool vr_flinger_enabled =
+      getBool<ISurfaceFlingerConfigs, &ISurfaceFlingerConfigs::useVrFlinger>(
+          false);
+  if (!vr_flinger_enabled) {
+    return;
+  }
+
+  // This test doesn't apply to standalone vr devices.
+  if (property_get_bool("ro.boot.vr", false)) {
+    return;
+  }
+
+  auto surface_flinger_connection = SurfaceFlingerConnection::Create();
+  ASSERT_NE(surface_flinger_connection, nullptr);
+
+  // Verify we start off with vr flinger disabled.
+  ASSERT_TRUE(surface_flinger_connection->IsAlive());
+  auto vr_flinger_active = surface_flinger_connection->IsVrFlingerActive();
+  ASSERT_TRUE(vr_flinger_active.has_value());
+  ASSERT_FALSE(vr_flinger_active.value());
+
+  // Create a vr flinger surface, and verify vr flinger becomes active.
+  // Introduce a scope so that, at the end of the scope, the vr flinger surface
+  // is destroyed, and vr flinger deactivates.
+  {
+    auto display_client = DisplayClient::Create();
+    ASSERT_NE(display_client, nullptr);
+    auto metrics = display_client->GetDisplayMetrics();
+    ASSERT_TRUE(metrics.ok());
+
+    auto surface = Surface::CreateSurface({
+        {SurfaceAttribute::Direct, SurfaceAttributeValue(true)},
+        {SurfaceAttribute::Visible, SurfaceAttributeValue(true)},
+    });
+    ASSERT_TRUE(surface.ok());
+    ASSERT_TRUE(surface.get() != nullptr);
+
+    auto queue = surface.get()->CreateQueue(
+        metrics.get().display_width, metrics.get().display_height,
+        /*layer_count=*/1, AHARDWAREBUFFER_FORMAT_R8G8B8X8_UNORM,
+        AHARDWAREBUFFER_USAGE_GPU_SAMPLED_IMAGE |
+            AHARDWAREBUFFER_USAGE_GPU_COLOR_OUTPUT |
+            AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+        /*capacity=*/1,
+        /*metadata_size=*/0);
+    ASSERT_TRUE(queue.ok());
+    ASSERT_TRUE(queue.get() != nullptr);
+
+    size_t slot;
+    pdx::LocalHandle release_fence;
+    auto buffer = queue.get()->Dequeue(/*timeout=*/0, &slot, &release_fence);
+    ASSERT_TRUE(buffer.ok());
+    ASSERT_TRUE(buffer.get() != nullptr);
+
+    ASSERT_EQ(buffer.get()->width(), metrics.get().display_width);
+    ASSERT_EQ(buffer.get()->height(), metrics.get().display_height);
+
+    void* raw_buf = nullptr;
+    ASSERT_GE(buffer.get()->Lock(AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN,
+                                 /*x=*/0, /*y=*/0, buffer.get()->width(),
+                                 buffer.get()->height(), &raw_buf),
+              0);
+    ASSERT_NE(raw_buf, nullptr);
+    uint32_t* pixels = static_cast<uint32_t*>(raw_buf);
+
+    for (int i = 0; i < buffer.get()->stride() * buffer.get()->height(); ++i) {
+      pixels[i] = 0x0000ff00;
+    }
+
+    ASSERT_GE(buffer.get()->Unlock(), 0);
+
+    ASSERT_GE(buffer.get()->Post(/*ready_fence=*/pdx::LocalHandle(),
+                                 /*meta=*/nullptr,
+                                 /*user_metadata_size=*/0),
+              0);
+
+    ASSERT_EQ(
+        surface_flinger_connection->WaitForVrFlinger(/*wait_active=*/true),
+        SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess);
+  }
+
+  // Now that the vr flinger surface is destroyed, vr flinger should deactivate.
+  ASSERT_EQ(
+      surface_flinger_connection->WaitForVrFlinger(/*wait_active=*/false),
+      SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess);
+}
+
+// This test runs only on devices that boot to vr. Such a device should boot to
+// a state where vr flinger is running, and the test verifies this after a
+// delay.
+TEST(BootVrFlingerTest, BootsToVrFlinger) {
+  // Exit if we are not running on a device that boots to vr.
+  if (!property_get_bool("ro.boot.vr", false)) {
+    return;
+  }
+
+  auto surface_flinger_connection = SurfaceFlingerConnection::Create();
+  ASSERT_NE(surface_flinger_connection, nullptr);
+
+  // Verify that vr flinger is enabled.
+  ASSERT_TRUE(surface_flinger_connection->IsAlive());
+  auto vr_flinger_active = surface_flinger_connection->IsVrFlingerActive();
+  ASSERT_TRUE(vr_flinger_active.has_value());
+
+  bool active_value = vr_flinger_active.value();
+  if (!active_value) {
+    // Try again, but delay up to 30 seconds.
+    ASSERT_EQ(surface_flinger_connection->WaitForVrFlingerTimed(true,
+        kVrFlingerSwitchPollInterval, kBootVrFlingerWaitTimeout),
+        SurfaceFlingerConnection::VrFlingerSwitchResult::kSuccess);
+  }
+}
+
+}  // namespace dvr
+}  // namespace android
diff --git a/libs/vr/libvrflinger/tests/vrflinger_test.filter b/libs/vr/libvrflinger/tests/vrflinger_test.filter
new file mode 100644
index 0000000..030bb7b
--- /dev/null
+++ b/libs/vr/libvrflinger/tests/vrflinger_test.filter
@@ -0,0 +1,5 @@
+{
+        "presubmit": {
+            "filter": "BootVrFlingerTest.*"
+        }
+}
diff --git a/libs/vr/libvrflinger/vr_flinger.cpp b/libs/vr/libvrflinger/vr_flinger.cpp
index 26aed4f..b57383a 100644
--- a/libs/vr/libvrflinger/vr_flinger.cpp
+++ b/libs/vr/libvrflinger/vr_flinger.cpp
@@ -23,7 +23,6 @@
 #include "DisplayHardware/ComposerHal.h"
 #include "display_manager_service.h"
 #include "display_service.h"
-#include "vsync_service.h"
 
 namespace android {
 namespace dvr {
@@ -85,16 +84,6 @@
   CHECK_ERROR(!service, error, "Failed to create display manager service.");
   dispatcher_->AddService(service);
 
-  service = android::dvr::VSyncService::Create();
-  CHECK_ERROR(!service, error, "Failed to create vsync service.");
-  dispatcher_->AddService(service);
-
-  display_service_->SetVSyncCallback(
-      std::bind(&android::dvr::VSyncService::VSyncEvent,
-                std::static_pointer_cast<android::dvr::VSyncService>(service),
-                std::placeholders::_1, std::placeholders::_2,
-                std::placeholders::_3));
-
   dispatcher_thread_ = std::thread([this]() {
     prctl(PR_SET_NAME, reinterpret_cast<unsigned long>("VrDispatch"), 0, 0, 0);
     ALOGI("Entering message loop.");
diff --git a/libs/vr/libvrflinger/vsync_service.cpp b/libs/vr/libvrflinger/vsync_service.cpp
deleted file mode 100644
index b8d8b08..0000000
--- a/libs/vr/libvrflinger/vsync_service.cpp
+++ /dev/null
@@ -1,212 +0,0 @@
-#include "vsync_service.h"
-
-#include <hardware/hwcomposer.h>
-#include <log/log.h>
-#include <poll.h>
-#include <sys/prctl.h>
-#include <time.h>
-#include <utils/Trace.h>
-
-#include <dvr/dvr_display_types.h>
-#include <pdx/default_transport/service_endpoint.h>
-#include <private/dvr/clock_ns.h>
-#include <private/dvr/display_protocol.h>
-
-using android::dvr::display::VSyncProtocol;
-using android::dvr::display::VSyncSchedInfo;
-using android::pdx::Channel;
-using android::pdx::Message;
-using android::pdx::MessageInfo;
-using android::pdx::default_transport::Endpoint;
-using android::pdx::rpc::DispatchRemoteMethod;
-
-namespace android {
-namespace dvr {
-
-VSyncService::VSyncService()
-    : BASE("VSyncService", Endpoint::Create(VSyncProtocol::kClientPath)),
-      last_vsync_(0),
-      current_vsync_(0),
-      compositor_time_ns_(0),
-      current_vsync_count_(0) {}
-
-VSyncService::~VSyncService() {}
-
-void VSyncService::VSyncEvent(int64_t timestamp_ns,
-                              int64_t compositor_time_ns,
-                              uint32_t vsync_count) {
-  ATRACE_NAME("VSyncService::VSyncEvent");
-  std::lock_guard<std::mutex> autolock(mutex_);
-
-  last_vsync_ = current_vsync_;
-  current_vsync_ = timestamp_ns;
-  compositor_time_ns_ = compositor_time_ns;
-  current_vsync_count_ = vsync_count;
-
-  NotifyWaiters();
-  UpdateClients();
-}
-
-std::shared_ptr<Channel> VSyncService::OnChannelOpen(pdx::Message& message) {
-  const MessageInfo& info = message.GetInfo();
-
-  auto client = std::make_shared<VSyncChannel>(*this, info.pid, info.cid);
-  AddClient(client);
-
-  return client;
-}
-
-void VSyncService::OnChannelClose(pdx::Message& /*message*/,
-                                  const std::shared_ptr<Channel>& channel) {
-  auto client = std::static_pointer_cast<VSyncChannel>(channel);
-  if (!client) {
-    ALOGW("WARNING: VSyncChannel was NULL!!!\n");
-    return;
-  }
-
-  RemoveClient(client);
-}
-
-void VSyncService::AddWaiter(pdx::Message& message) {
-  std::lock_guard<std::mutex> autolock(mutex_);
-  std::unique_ptr<VSyncWaiter> waiter(new VSyncWaiter(message));
-  waiters_.push_back(std::move(waiter));
-}
-
-void VSyncService::AddClient(const std::shared_ptr<VSyncChannel>& client) {
-  std::lock_guard<std::mutex> autolock(mutex_);
-  clients_.push_back(client);
-}
-
-void VSyncService::RemoveClient(const std::shared_ptr<VSyncChannel>& client) {
-  std::lock_guard<std::mutex> autolock(mutex_);
-  clients_.remove(client);
-}
-
-// Private. Assumes mutex is held.
-void VSyncService::NotifyWaiters() {
-  ATRACE_NAME("VSyncService::NotifyWaiters");
-  auto first = waiters_.begin();
-  auto last = waiters_.end();
-
-  while (first != last) {
-    (*first)->Notify(current_vsync_);
-    waiters_.erase(first++);
-  }
-}
-
-// Private. Assumes mutex is held.
-void VSyncService::UpdateClients() {
-  ATRACE_NAME("VSyncService::UpdateClients");
-  auto first = clients_.begin();
-  auto last = clients_.end();
-
-  while (first != last) {
-    (*first)->Signal();
-    first++;
-  }
-}
-
-pdx::Status<void> VSyncService::HandleMessage(pdx::Message& message) {
-  ATRACE_NAME("VSyncService::HandleMessage");
-  switch (message.GetOp()) {
-    case VSyncProtocol::Wait::Opcode:
-      AddWaiter(message);
-      return {};
-
-    case VSyncProtocol::GetLastTimestamp::Opcode:
-      DispatchRemoteMethod<VSyncProtocol::GetLastTimestamp>(
-          *this, &VSyncService::OnGetLastTimestamp, message);
-      return {};
-
-    case VSyncProtocol::GetSchedInfo::Opcode:
-      DispatchRemoteMethod<VSyncProtocol::GetSchedInfo>(
-          *this, &VSyncService::OnGetSchedInfo, message);
-      return {};
-
-    case VSyncProtocol::Acknowledge::Opcode:
-      DispatchRemoteMethod<VSyncProtocol::Acknowledge>(
-          *this, &VSyncService::OnAcknowledge, message);
-      return {};
-
-    default:
-      return Service::HandleMessage(message);
-  }
-}
-
-pdx::Status<int64_t> VSyncService::OnGetLastTimestamp(pdx::Message& message) {
-  auto client = std::static_pointer_cast<VSyncChannel>(message.GetChannel());
-  std::lock_guard<std::mutex> autolock(mutex_);
-
-  // Getting the timestamp has the side effect of ACKing.
-  client->Ack();
-  return {current_vsync_};
-}
-
-pdx::Status<VSyncSchedInfo> VSyncService::OnGetSchedInfo(
-    pdx::Message& message) {
-  auto client = std::static_pointer_cast<VSyncChannel>(message.GetChannel());
-  std::lock_guard<std::mutex> autolock(mutex_);
-
-  // Getting the timestamp has the side effect of ACKing.
-  client->Ack();
-
-  uint32_t next_vsync_count = current_vsync_count_ + 1;
-  int64_t current_time = GetSystemClockNs();
-  int64_t vsync_period_ns = 0;
-  int64_t next_warp;
-  if (current_vsync_ == 0 || last_vsync_ == 0) {
-    // Handle startup when current_vsync_ or last_vsync_ are 0.
-    // Normally should not happen because vsync_service is running before
-    // applications, but in case it does a sane time prevents applications
-    // from malfunctioning.
-    vsync_period_ns = 20000000;
-    next_warp = current_time;
-  } else {
-    // TODO(jbates) When we have an accurate reading of the true vsync
-    // period, use that instead of this estimated value.
-    vsync_period_ns = current_vsync_ - last_vsync_;
-    // Clamp the period, because when there are no surfaces the last_vsync_
-    // value will get stale. Note this is temporary and goes away as soon
-    // as we have an accurate vsync period reported by the system.
-    vsync_period_ns = std::min(vsync_period_ns, INT64_C(20000000));
-    next_warp = current_vsync_ + vsync_period_ns - compositor_time_ns_;
-    // If the request missed the present window, move up to the next vsync.
-    if (current_time > next_warp) {
-      next_warp += vsync_period_ns;
-      ++next_vsync_count;
-    }
-  }
-
-  return {{vsync_period_ns, next_warp, next_vsync_count}};
-}
-
-pdx::Status<void> VSyncService::OnAcknowledge(pdx::Message& message) {
-  auto client = std::static_pointer_cast<VSyncChannel>(message.GetChannel());
-  std::lock_guard<std::mutex> autolock(mutex_);
-  client->Ack();
-  return {};
-}
-
-void VSyncWaiter::Notify(int64_t timestamp) {
-  timestamp_ = timestamp;
-  DispatchRemoteMethod<VSyncProtocol::Wait>(*this, &VSyncWaiter::OnWait,
-                                            message_);
-}
-
-pdx::Status<int64_t> VSyncWaiter::OnWait(pdx::Message& /*message*/) {
-  return {timestamp_};
-}
-
-void VSyncChannel::Ack() {
-  ALOGD_IF(TRACE > 1, "VSyncChannel::Ack: pid=%d cid=%d\n", pid_, cid_);
-  service_.ModifyChannelEvents(cid_, POLLPRI, 0);
-}
-
-void VSyncChannel::Signal() {
-  ALOGD_IF(TRACE > 1, "VSyncChannel::Signal: pid=%d cid=%d\n", pid_, cid_);
-  service_.ModifyChannelEvents(cid_, 0, POLLPRI);
-}
-
-}  // namespace dvr
-}  // namespace android
diff --git a/libs/vr/libvrflinger/vsync_service.h b/libs/vr/libvrflinger/vsync_service.h
deleted file mode 100644
index 822f02b..0000000
--- a/libs/vr/libvrflinger/vsync_service.h
+++ /dev/null
@@ -1,107 +0,0 @@
-#ifndef ANDROID_DVR_SERVICES_DISPLAYD_VSYNC_SERVICE_H_
-#define ANDROID_DVR_SERVICES_DISPLAYD_VSYNC_SERVICE_H_
-
-#include <pdx/service.h>
-
-#include <list>
-#include <memory>
-#include <mutex>
-#include <thread>
-
-#include "display_service.h"
-
-namespace android {
-namespace dvr {
-
-// VSyncWaiter encapsulates a client blocked waiting for the next vsync.
-// It is used to enqueue the Message to reply to when the next vsync event
-// occurs.
-class VSyncWaiter {
- public:
-  explicit VSyncWaiter(pdx::Message& message) : message_(std::move(message)) {}
-
-  void Notify(int64_t timestamp);
-
- private:
-  pdx::Status<int64_t> OnWait(pdx::Message& message);
-
-  pdx::Message message_;
-  int64_t timestamp_ = 0;
-
-  VSyncWaiter(const VSyncWaiter&) = delete;
-  void operator=(const VSyncWaiter&) = delete;
-};
-
-// VSyncChannel manages the service-side per-client context for each client
-// using the service.
-class VSyncChannel : public pdx::Channel {
- public:
-  VSyncChannel(pdx::Service& service, int pid, int cid)
-      : service_(service), pid_(pid), cid_(cid) {}
-
-  void Ack();
-  void Signal();
-
- private:
-  pdx::Service& service_;
-  pid_t pid_;
-  int cid_;
-
-  VSyncChannel(const VSyncChannel&) = delete;
-  void operator=(const VSyncChannel&) = delete;
-};
-
-// VSyncService implements the displayd vsync service over ServiceFS.
-class VSyncService : public pdx::ServiceBase<VSyncService> {
- public:
-  ~VSyncService() override;
-
-  pdx::Status<void> HandleMessage(pdx::Message& message) override;
-
-  std::shared_ptr<pdx::Channel> OnChannelOpen(pdx::Message& message) override;
-  void OnChannelClose(pdx::Message& message,
-                      const std::shared_ptr<pdx::Channel>& channel) override;
-
-  // Called by the hardware composer HAL, or similar, whenever a vsync event
-  // occurs on the primary display. |compositor_time_ns| is the number of ns
-  // before the next vsync when the compositor will preempt the GPU to do EDS
-  // and lens warp.
-  void VSyncEvent(int64_t timestamp_ns, int64_t compositor_time_ns,
-                  uint32_t vsync_count);
-
- private:
-  friend BASE;
-
-  VSyncService();
-
-  pdx::Status<int64_t> OnGetLastTimestamp(pdx::Message& message);
-  pdx::Status<display::VSyncSchedInfo> OnGetSchedInfo(pdx::Message& message);
-  pdx::Status<void> OnAcknowledge(pdx::Message& message);
-
-  void NotifierThreadFunction();
-
-  void AddWaiter(pdx::Message& message);
-  void NotifyWaiters();
-  void UpdateClients();
-
-  void AddClient(const std::shared_ptr<VSyncChannel>& client);
-  void RemoveClient(const std::shared_ptr<VSyncChannel>& client);
-
-  int64_t last_vsync_;
-  int64_t current_vsync_;
-  int64_t compositor_time_ns_;
-  uint32_t current_vsync_count_;
-
-  std::mutex mutex_;
-
-  std::list<std::unique_ptr<VSyncWaiter>> waiters_;
-  std::list<std::shared_ptr<VSyncChannel>> clients_;
-
-  VSyncService(const VSyncService&) = delete;
-  void operator=(VSyncService&) = delete;
-};
-
-}  // namespace dvr
-}  // namespace android
-
-#endif  // ANDROID_DVR_SERVICES_DISPLAYD_VSYNC_SERVICE_H_
diff --git a/opengl/include/EGL/eglext.h b/opengl/include/EGL/eglext.h
index 44f4dbc..0fd91eb 100644
--- a/opengl/include/EGL/eglext.h
+++ b/opengl/include/EGL/eglext.h
@@ -1285,17 +1285,6 @@
 #define EGL_NATIVE_SURFACE_TIZEN          0x32A1
 #endif /* EGL_TIZEN_image_native_surface */
 
-/* This is a private Android extension that does not exist in the EGL registry,
- * formerly used to work around a hardware issue on Nexus 4. It is deprecated
- * and unimplemented. It has been added to this header manually. */
-#ifndef EGL_ANDROID_image_crop
-#define EGL_ANDROID_image_crop 1
-#define EGL_IMAGE_CROP_LEFT_ANDROID       0x3148
-#define EGL_IMAGE_CROP_TOP_ANDROID        0x3149
-#define EGL_IMAGE_CROP_RIGHT_ANDROID      0x314A
-#define EGL_IMAGE_CROP_BOTTOM_ANDROID     0x314B
-#endif
-
 #ifdef __cplusplus
 }
 #endif
diff --git a/opengl/libs/EGL/BlobCache.cpp b/opengl/libs/EGL/BlobCache.cpp
index b3752f5..74c4d7d 100644
--- a/opengl/libs/EGL/BlobCache.cpp
+++ b/opengl/libs/EGL/BlobCache.cpp
@@ -79,7 +79,7 @@
     }
 
     std::shared_ptr<Blob> dummyKey(new Blob(key, keySize, false));
-    CacheEntry dummyEntry(dummyKey, NULL);
+    CacheEntry dummyEntry(dummyKey, nullptr);
 
     while (true) {
         auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), dummyEntry);
@@ -139,7 +139,7 @@
         return 0;
     }
     std::shared_ptr<Blob> dummyKey(new Blob(key, keySize, false));
-    CacheEntry dummyEntry(dummyKey, NULL);
+    CacheEntry dummyEntry(dummyKey, nullptr);
     auto index = std::lower_bound(mCacheEntries.begin(), mCacheEntries.end(), dummyEntry);
     if (index == mCacheEntries.end() || dummyEntry < *index) {
         ALOGV("get: no cache entry found for key of size %zu", keySize);
@@ -308,7 +308,7 @@
         mData(copyData ? malloc(size) : data),
         mSize(size),
         mOwnsData(copyData) {
-    if (data != NULL && copyData) {
+    if (data != nullptr && copyData) {
         memcpy(const_cast<void*>(mData), data, size);
     }
 }
diff --git a/opengl/libs/EGL/BlobCache_test.cpp b/opengl/libs/EGL/BlobCache_test.cpp
index edbaaf0..cf67cf4 100644
--- a/opengl/libs/EGL/BlobCache_test.cpp
+++ b/opengl/libs/EGL/BlobCache_test.cpp
@@ -97,7 +97,7 @@
 
 TEST_F(BlobCacheTest, GetDoesntAccessNullBuffer) {
     mBC->set("abcd", 4, "efgh", 4);
-    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, NULL, 0));
+    ASSERT_EQ(size_t(4), mBC->get("abcd", 4, nullptr, 0));
 }
 
 TEST_F(BlobCacheTest, MultipleSetsCacheLatestValue) {
@@ -169,7 +169,7 @@
     }
 
     mBC->set(key, MAX_KEY_SIZE, buf, MAX_VALUE_SIZE);
-    ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+    ASSERT_EQ(size_t(0), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
 }
 
 TEST_F(BlobCacheTest, CacheMaxKeySizeSucceeds) {
@@ -219,7 +219,7 @@
     }
 
     mBC->set(key, MAX_KEY_SIZE, buf, bufSize);
-    ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, NULL, 0));
+    ASSERT_EQ(size_t(bufSize), mBC->get(key, MAX_KEY_SIZE, nullptr, 0));
 }
 
 TEST_F(BlobCacheTest, CacheMinKeyAndValueSizeSucceeds) {
@@ -237,7 +237,7 @@
     int numCached = 0;
     for (int i = 0; i < 256; i++) {
         uint8_t k = i;
-        if (mBC->get(&k, 1, NULL, 0) == 1) {
+        if (mBC->get(&k, 1, nullptr, 0) == 1) {
             numCached++;
         }
     }
@@ -260,7 +260,7 @@
     int numCached = 0;
     for (int i = 0; i < maxEntries+1; i++) {
         uint8_t k = i;
-        if (mBC->get(&k, 1, NULL, 0) == 1) {
+        if (mBC->get(&k, 1, nullptr, 0) == 1) {
             numCached++;
         }
     }
diff --git a/opengl/libs/EGL/FileBlobCache.cpp b/opengl/libs/EGL/FileBlobCache.cpp
index 7923715..cc42ac7 100644
--- a/opengl/libs/EGL/FileBlobCache.cpp
+++ b/opengl/libs/EGL/FileBlobCache.cpp
@@ -77,7 +77,7 @@
             return;
         }
 
-        uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(NULL, fileSize,
+        uint8_t* buf = reinterpret_cast<uint8_t*>(mmap(nullptr, fileSize,
                 PROT_READ, MAP_PRIVATE, fd, 0));
         if (buf == MAP_FAILED) {
             ALOGE("error mmaping cache file: %s (%d)", strerror(errno),
diff --git a/opengl/libs/EGL/Loader.cpp b/opengl/libs/EGL/Loader.cpp
index 91a3455..e954b4f 100644
--- a/opengl/libs/EGL/Loader.cpp
+++ b/opengl/libs/EGL/Loader.cpp
@@ -129,7 +129,7 @@
 {
     dso[0] = gles;
     for (size_t i=1 ; i<NELEM(dso) ; i++)
-        dso[i] = 0;
+        dso[i] = nullptr;
 }
 
 Loader::driver_t::~driver_t()
@@ -137,7 +137,7 @@
     for (size_t i=0 ; i<NELEM(dso) ; i++) {
         if (dso[i]) {
             dlclose(dso[i]);
-            dso[i] = 0;
+            dso[i] = nullptr;
         }
     }
 }
@@ -163,7 +163,7 @@
 // ----------------------------------------------------------------------------
 
 Loader::Loader()
-    : getProcAddress(NULL)
+    : getProcAddress(nullptr)
 {
 }
 
@@ -221,7 +221,7 @@
     ATRACE_CALL();
 
     void* dso;
-    driver_t* hnd = 0;
+    driver_t* hnd = nullptr;
 
     setEmulatorGlesValue();
 
@@ -272,11 +272,11 @@
         char const * name = *api;
         __eglMustCastToProperFunctionPointerType f =
             (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
-        if (f == NULL) {
+        if (f == nullptr) {
             // couldn't find the entry-point, use eglGetProcAddress()
             f = getProcAddress(name);
         }
-        if (f == NULL) {
+        if (f == nullptr) {
             // Try without the OES postfix
             ssize_t index = ssize_t(strlen(name)) - 3;
             if ((index>0 && (index<SIZE-1)) && (!strcmp(name+index, "OES"))) {
@@ -286,7 +286,7 @@
                 //ALOGD_IF(f, "found <%s> instead", scrap);
             }
         }
-        if (f == NULL) {
+        if (f == nullptr) {
             // Try with the OES postfix
             ssize_t index = ssize_t(strlen(name)) - 3;
             if (index>0 && strcmp(name+index, "OES")) {
@@ -295,7 +295,7 @@
                 //ALOGD_IF(f, "found <%s> instead", scrap);
             }
         }
-        if (f == NULL) {
+        if (f == nullptr) {
             //ALOGD("%s", name);
             f = (__eglMustCastToProperFunctionPointerType)gl_unimplemented;
 
@@ -406,9 +406,9 @@
             }
 
             DIR* d = opendir(search);
-            if (d != NULL) {
+            if (d != nullptr) {
                 struct dirent* e;
-                while ((e = readdir(d)) != NULL) {
+                while ((e = readdir(d)) != nullptr) {
                     if (e->d_type == DT_DIR) {
                         continue;
                     }
@@ -434,7 +434,7 @@
     std::string absolutePath = MatchFile::find(kind);
     if (absolutePath.empty()) {
         // this happens often, we don't want to log an error
-        return 0;
+        return nullptr;
     }
     const char* const driver_absolute_path = absolutePath.c_str();
 
@@ -444,10 +444,10 @@
     // sphal namespace.
     void* dso = do_android_load_sphal_library(driver_absolute_path,
                                               RTLD_NOW | RTLD_LOCAL);
-    if (dso == 0) {
+    if (dso == nullptr) {
         const char* err = dlerror();
         ALOGE("load_driver(%s): %s", driver_absolute_path, err ? err : "unknown");
-        return 0;
+        return nullptr;
     }
 
     ALOGD("loaded %s", driver_absolute_path);
@@ -495,7 +495,7 @@
     if (!dso) {
         dso = load_system_driver(kind);
         if (!dso)
-            return NULL;
+            return nullptr;
     }
 
     if (mask & EGL) {
@@ -512,11 +512,11 @@
             char const * name = *api;
             __eglMustCastToProperFunctionPointerType f =
                 (__eglMustCastToProperFunctionPointerType)dlsym(dso, name);
-            if (f == NULL) {
+            if (f == nullptr) {
                 // couldn't find the entry-point, use eglGetProcAddress()
                 f = getProcAddress(name);
-                if (f == NULL) {
-                    f = (__eglMustCastToProperFunctionPointerType)0;
+                if (f == nullptr) {
+                    f = (__eglMustCastToProperFunctionPointerType)nullptr;
                 }
             }
             *curr++ = f;
diff --git a/opengl/libs/EGL/egl.cpp b/opengl/libs/EGL/egl.cpp
index f53cf3f..e292b80 100644
--- a/opengl/libs/EGL/egl.cpp
+++ b/opengl/libs/EGL/egl.cpp
@@ -89,22 +89,22 @@
 egl_display_ptr validate_display(EGLDisplay dpy) {
     egl_display_ptr dp = get_display(dpy);
     if (!dp)
-        return setError(EGL_BAD_DISPLAY, egl_display_ptr(NULL));
+        return setError(EGL_BAD_DISPLAY, egl_display_ptr(nullptr));
     if (!dp->isReady())
-        return setError(EGL_NOT_INITIALIZED, egl_display_ptr(NULL));
+        return setError(EGL_NOT_INITIALIZED, egl_display_ptr(nullptr));
 
     return dp;
 }
 
 egl_display_ptr validate_display_connection(EGLDisplay dpy,
         egl_connection_t*& cnx) {
-    cnx = NULL;
+    cnx = nullptr;
     egl_display_ptr dp = validate_display(dpy);
     if (!dp)
         return dp;
     cnx = &gEGLImpl;
-    if (cnx->dso == 0) {
-        return setError(EGL_BAD_CONFIG, egl_display_ptr(NULL));
+    if (cnx->dso == nullptr) {
+        return setError(EGL_BAD_CONFIG, egl_display_ptr(nullptr));
     }
     return dp;
 }
@@ -117,14 +117,14 @@
 
     EGLContext context = egl_tls_t::getContext();
     if (context == EGL_NO_CONTEXT)
-        return NULL;
+        return nullptr;
 
     egl_context_t const * const c = get_context(context);
-    if (c == NULL) // this should never happen, by construction
-        return NULL;
+    if (c == nullptr) // this should never happen, by construction
+        return nullptr;
 
     if (name != GL_EXTENSIONS)
-        return NULL;
+        return nullptr;
 
     return (const GLubyte *)c->gl_extensions.c_str();
 }
@@ -135,19 +135,19 @@
 
     EGLContext context = egl_tls_t::getContext();
     if (context == EGL_NO_CONTEXT)
-        return NULL;
+        return nullptr;
 
     egl_context_t const * const c = get_context(context);
-    if (c == NULL) // this should never happen, by construction
-        return NULL;
+    if (c == nullptr) // this should never happen, by construction
+        return nullptr;
 
     if (name != GL_EXTENSIONS)
-        return NULL;
+        return nullptr;
 
     // if index is out of bounds, assume it will be in the default
     // implementation too, so we don't have to generate a GL error here
     if (index >= c->tokenized_gl_extensions.size())
-        return NULL;
+        return nullptr;
 
     return (const GLubyte *)c->tokenized_gl_extensions[index].c_str();
 }
@@ -161,7 +161,7 @@
         return -1;
 
     egl_context_t const * const c = get_context(context);
-    if (c == NULL) // this should never happen, by construction
+    if (c == nullptr) // this should never happen, by construction
         return -1;
 
     return (GLint)c->tokenized_gl_extensions.size();
@@ -184,7 +184,7 @@
 
     // dynamically load our EGL implementation
     egl_connection_t* cnx = &gEGLImpl;
-    if (cnx->dso == 0) {
+    if (cnx->dso == nullptr) {
         cnx->hooks[egl_connection_t::GLESv1_INDEX] =
                 &gHooks[egl_connection_t::GLESv1_INDEX];
         cnx->hooks[egl_connection_t::GLESv2_INDEX] =
@@ -249,12 +249,12 @@
 
 char const * const gl_names[] = {
     #include "../entries.in"
-    NULL
+    nullptr
 };
 
 char const * const egl_names[] = {
     #include "egl_entries.in"
-    NULL
+    nullptr
 };
 
 #undef GL_ENTRY
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index c65bddf..c361ab0 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -136,7 +136,6 @@
 //      "EGL_IMG_hibernate_process "            // optional
 //      "EGL_ANDROID_native_fence_sync "        // strongly recommended
 //      "EGL_ANDROID_framebuffer_target "       // mandatory for HWC 1.1
-//      "EGL_ANDROID_image_crop "               // optional
 
 /*
  * EGL Extensions entry-points exposed to 3rd party applications
@@ -258,7 +257,7 @@
             return map[i].address;
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 // ----------------------------------------------------------------------------
@@ -341,7 +340,7 @@
     const egl_display_ptr dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    if (num_config==0) {
+    if (num_config==nullptr) {
         return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
     }
 
@@ -366,7 +365,7 @@
     const egl_display_ptr dp = validate_display(dpy);
     if (!dp) return EGL_FALSE;
 
-    if (num_config==0) {
+    if (num_config==nullptr) {
         return setError(EGL_BAD_PARAMETER, (EGLBoolean)EGL_FALSE);
     }
 
@@ -385,8 +384,8 @@
 
                 // Only enable MSAA if the context is OpenGL ES 2.0 and
                 // if no caveat is requested
-                const EGLint *attribRendererable = NULL;
-                const EGLint *attribCaveat = NULL;
+                const EGLint *attribRendererable = nullptr;
+                const EGLint *attribCaveat = nullptr;
 
                 // Count the number of attributes and look for
                 // EGL_RENDERABLE_TYPE and EGL_CONFIG_CAVEAT
@@ -441,7 +440,7 @@
 {
     clearError();
 
-    egl_connection_t* cnx = NULL;
+    egl_connection_t* cnx = nullptr;
     const egl_display_ptr dp = validate_display_connection(dpy, cnx);
     if (!dp) return EGL_FALSE;
 
@@ -456,7 +455,7 @@
 // Translates EGL color spaces to Android data spaces.
 static android_dataspace dataSpaceFromEGLColorSpace(EGLint colorspace) {
     if (colorspace == EGL_GL_COLORSPACE_LINEAR_KHR) {
-        return HAL_DATASPACE_SRGB_LINEAR;
+        return HAL_DATASPACE_UNKNOWN;
     } else if (colorspace == EGL_GL_COLORSPACE_SRGB_KHR) {
         return HAL_DATASPACE_SRGB;
     } else if (colorspace == EGL_GL_COLORSPACE_DISPLAY_P3_EXT) {
@@ -699,7 +698,7 @@
     const EGLint *origAttribList = attrib_list;
     clearError();
 
-    egl_connection_t* cnx = NULL;
+    egl_connection_t* cnx = nullptr;
     egl_display_ptr dp = validate_display_connection(dpy, cnx);
     if (dp) {
         if (!window) {
@@ -782,7 +781,7 @@
 {
     clearError();
 
-    egl_connection_t* cnx = NULL;
+    egl_connection_t* cnx = nullptr;
     egl_display_ptr dp = validate_display_connection(dpy, cnx);
     if (dp) {
         EGLDisplay iDpy = dp->disp.dpy;
@@ -803,7 +802,7 @@
                 dp->disp.dpy, config, pixmap, attrib_list);
         if (surface != EGL_NO_SURFACE) {
             egl_surface_t* s =
-                    new egl_surface_t(dp.get(), config, NULL, surface,
+                    new egl_surface_t(dp.get(), config, nullptr, surface,
                                       getReportedColorSpace(colorSpace), cnx);
             return s;
         }
@@ -816,7 +815,7 @@
 {
     clearError();
 
-    egl_connection_t* cnx = NULL;
+    egl_connection_t* cnx = nullptr;
     egl_display_ptr dp = validate_display_connection(dpy, cnx);
     if (dp) {
         EGLDisplay iDpy = dp->disp.dpy;
@@ -837,7 +836,7 @@
                 dp->disp.dpy, config, attrib_list);
         if (surface != EGL_NO_SURFACE) {
             egl_surface_t* s =
-                    new egl_surface_t(dp.get(), config, NULL, surface,
+                    new egl_surface_t(dp.get(), config, nullptr, surface,
                                       getReportedColorSpace(colorSpace), cnx);
             return s;
         }
@@ -911,7 +910,7 @@
 {
     clearError();
 
-    egl_connection_t* cnx = NULL;
+    egl_connection_t* cnx = nullptr;
     const egl_display_ptr dp = validate_display_connection(dpy, cnx);
     if (dp) {
         if (share_list != EGL_NO_CONTEXT) {
@@ -1000,9 +999,9 @@
     EGLSurface impl_read = EGL_NO_SURFACE;
 
     // these are our objects structs passed in
-    egl_context_t       * c = NULL;
-    egl_surface_t const * d = NULL;
-    egl_surface_t const * r = NULL;
+    egl_context_t       * c = nullptr;
+    egl_surface_t const * d = nullptr;
+    egl_surface_t const * r = nullptr;
 
     // these are the current objects structs
     egl_context_t * cur_c = get_context(getContext());
@@ -1016,7 +1015,7 @@
             // calling eglMakeCurrent( ..., !=0, !=0, EGL_NO_CONTEXT);
             return setError(EGL_BAD_MATCH, (EGLBoolean)EGL_FALSE);
         }
-        if (cur_c == NULL) {
+        if (cur_c == nullptr) {
             // no current context
             // not an error, there is just no current context.
             return EGL_TRUE;
@@ -1054,38 +1053,6 @@
             egl_tls_t::setContext(EGL_NO_CONTEXT);
         }
     } else {
-
-        if (cur_c != NULL) {
-            // Force return to current context for drivers that cannot handle errors
-            EGLBoolean restore_result = EGL_FALSE;
-            // get a reference to the old current objects
-            ContextRef _c2(dp.get(), cur_c);
-            SurfaceRef _d2(dp.get(), cur_c->draw);
-            SurfaceRef _r2(dp.get(), cur_c->read);
-
-            c = cur_c;
-            impl_ctx = c->context;
-            impl_draw = EGL_NO_SURFACE;
-            if (cur_c->draw != EGL_NO_SURFACE) {
-                d = get_surface(cur_c->draw);
-                impl_draw = d->surface;
-            }
-            impl_read = EGL_NO_SURFACE;
-            if (cur_c->read != EGL_NO_SURFACE) {
-                r = get_surface(cur_c->read);
-                impl_read = r->surface;
-            }
-            restore_result = dp->makeCurrent(c, cur_c,
-                    cur_c->draw, cur_c->read, cur_c->context,
-                    impl_draw, impl_read, impl_ctx);
-            if (restore_result == EGL_TRUE) {
-                _c2.acquire();
-                _r2.acquire();
-                _d2.acquire();
-            } else {
-                ALOGE("Could not restore original EGL context");
-            }
-        }
         // this will ALOGE the error
         egl_connection_t* const cnx = &gEGLImpl;
         result = setError(cnx->egl.eglGetError(), (EGLBoolean)EGL_FALSE);
@@ -1196,7 +1163,7 @@
 static __eglMustCastToProperFunctionPointerType findBuiltinWrapper(
         const char* procname) {
     const egl_connection_t* cnx = &gEGLImpl;
-    void* proc = NULL;
+    void* proc = nullptr;
 
     proc = dlsym(cnx->libEgl, procname);
     if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
@@ -1207,7 +1174,7 @@
     proc = dlsym(cnx->libGles1, procname);
     if (proc) return (__eglMustCastToProperFunctionPointerType)proc;
 
-    return NULL;
+    return nullptr;
 }
 
 __eglMustCastToProperFunctionPointerType eglGetProcAddress(const char *procname)
@@ -1220,11 +1187,11 @@
 
     if (egl_init_drivers() == EGL_FALSE) {
         setError(EGL_BAD_PARAMETER, NULL);
-        return  NULL;
+        return  nullptr;
     }
 
     if (FILTER_EXTENSIONS(procname)) {
-        return NULL;
+        return nullptr;
     }
 
     __eglMustCastToProperFunctionPointerType addr;
@@ -1379,7 +1346,7 @@
     egl_surface_t* const s = get_surface(draw);
 
     if (CC_UNLIKELY(dp->traceGpuCompletion)) {
-        EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, NULL);
+        EGLSyncKHR sync = eglCreateSyncKHR(dpy, EGL_SYNC_FENCE_KHR, nullptr);
         if (sync != EGL_NO_SYNC_KHR) {
             FrameCompletionThread::queueSync(sync);
         }
@@ -1430,7 +1397,7 @@
 
 EGLBoolean eglSwapBuffers(EGLDisplay dpy, EGLSurface surface)
 {
-    return eglSwapBuffersWithDamageKHR(dpy, surface, NULL, 0);
+    return eglSwapBuffersWithDamageKHR(dpy, surface, nullptr, 0);
 }
 
 EGLBoolean eglCopyBuffers(  EGLDisplay dpy, EGLSurface surface,
@@ -1461,10 +1428,10 @@
     // If we want to support EGL_EXT_client_extensions later, we can return
     // the client extension string here instead.
     if (dpy == EGL_NO_DISPLAY && name == EGL_EXTENSIONS)
-        return setErrorQuiet(EGL_BAD_DISPLAY, (const char*)0);
+        return setErrorQuiet(EGL_BAD_DISPLAY, (const char*)nullptr);
 
     const egl_display_ptr dp = validate_display(dpy);
-    if (!dp) return (const char *) NULL;
+    if (!dp) return (const char *) nullptr;
 
     switch (name) {
         case EGL_VENDOR:
@@ -1478,7 +1445,7 @@
         default:
             break;
     }
-    return setError(EGL_BAD_PARAMETER, (const char *)0);
+    return setError(EGL_BAD_PARAMETER, (const char *)nullptr);
 }
 
 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name)
@@ -1486,7 +1453,7 @@
     clearError();
 
     const egl_display_ptr dp = validate_display(dpy);
-    if (!dp) return (const char *) NULL;
+    if (!dp) return (const char *) nullptr;
 
     switch (name) {
         case EGL_VENDOR:
@@ -1500,7 +1467,7 @@
         default:
             break;
     }
-    return setError(EGL_BAD_PARAMETER, (const char *)0);
+    return setError(EGL_BAD_PARAMETER, (const char *)nullptr);
 }
 
 // ----------------------------------------------------------------------------
@@ -1682,7 +1649,7 @@
 {
     clearError();
 
-    egl_connection_t* cnx = NULL;
+    egl_connection_t* cnx = nullptr;
     const egl_display_ptr dp = validate_display_connection(dpy, cnx);
     if (!dp) return EGL_FALSE;
     if (cnx->egl.eglCreatePbufferFromClientBuffer) {
@@ -1745,31 +1712,13 @@
     ContextRef _c(dp.get(), ctx);
     egl_context_t * const c = _c.get();
 
-    // Temporary hack: eglImageCreateKHR should accept EGL_GL_COLORSPACE_LINEAR_KHR,
-    // EGL_GL_COLORSPACE_SRGB_KHR and EGL_GL_COLORSPACE_DEFAULT_EXT if
-    // EGL_EXT_image_gl_colorspace is supported, but some drivers don't like
-    // the DEFAULT value and generate an error.
-    std::vector<EGLint> strippedAttribList;
-    for (const EGLint *attr = attrib_list; attr && attr[0] != EGL_NONE; attr += 2) {
-        if (attr[0] == EGL_GL_COLORSPACE_KHR &&
-            dp->haveExtension("EGL_EXT_image_gl_colorspace")) {
-            if (attr[1] != EGL_GL_COLORSPACE_LINEAR_KHR &&
-                attr[1] != EGL_GL_COLORSPACE_SRGB_KHR) {
-                continue;
-            }
-        }
-        strippedAttribList.push_back(attr[0]);
-        strippedAttribList.push_back(attr[1]);
-    }
-    strippedAttribList.push_back(EGL_NONE);
-
     EGLImageKHR result = EGL_NO_IMAGE_KHR;
     egl_connection_t* const cnx = &gEGLImpl;
     if (cnx->dso && cnx->egl.eglCreateImageKHR) {
         result = cnx->egl.eglCreateImageKHR(
                 dp->disp.dpy,
                 c ? c->context : EGL_NO_CONTEXT,
-                target, buffer, strippedAttribList.data());
+                target, buffer, attrib_list);
     }
     return result;
 }
@@ -1986,7 +1935,7 @@
         EGLSurface surface = cnx->egl.eglCreateStreamProducerSurfaceKHR(
                 dp->disp.dpy, config, stream, attrib_list);
         if (surface != EGL_NO_SURFACE) {
-            egl_surface_t* s = new egl_surface_t(dp.get(), config, NULL, surface,
+            egl_surface_t* s = new egl_surface_t(dp.get(), config, nullptr, surface,
                                                  EGL_GL_COLORSPACE_LINEAR_KHR, cnx);
             return s;
         }
@@ -2142,10 +2091,10 @@
     // this function cannot be implemented when this libEGL is built for
     // vendors.
 #ifndef __ANDROID_VNDK__
-    if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
+    if (!buffer) return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr);
     return const_cast<ANativeWindowBuffer *>(AHardwareBuffer_to_ANativeWindowBuffer(buffer));
 #else
-    return setError(EGL_BAD_PARAMETER, (EGLClientBuffer)0);
+    return setError(EGL_BAD_PARAMETER, (EGLClientBuffer) nullptr);
 #endif
 }
 
diff --git a/opengl/libs/EGL/egl_cache.cpp b/opengl/libs/EGL/egl_cache.cpp
index ec548f3..bcf4961 100644
--- a/opengl/libs/EGL/egl_cache.cpp
+++ b/opengl/libs/EGL/egl_cache.cpp
@@ -95,7 +95,7 @@
                     reinterpret_cast<PFNEGLSETBLOBCACHEFUNCSANDROIDPROC>(
                             cnx->egl.eglGetProcAddress(
                                     "eglSetBlobCacheFuncsANDROID"));
-            if (eglSetBlobCacheFuncsANDROID == NULL) {
+            if (eglSetBlobCacheFuncsANDROID == nullptr) {
                 ALOGE("EGL_ANDROID_blob_cache advertised, "
                         "but unable to get eglSetBlobCacheFuncsANDROID");
                 return;
@@ -119,7 +119,7 @@
     if (mBlobCache) {
         mBlobCache->writeToFile();
     }
-    mBlobCache = NULL;
+    mBlobCache = nullptr;
 }
 
 void egl_cache_t::setBlob(const void* key, EGLsizeiANDROID keySize,
diff --git a/opengl/libs/EGL/egl_display.cpp b/opengl/libs/EGL/egl_display.cpp
index 2aec249..d16d33a 100644
--- a/opengl/libs/EGL/egl_display.cpp
+++ b/opengl/libs/EGL/egl_display.cpp
@@ -116,7 +116,7 @@
 
 EGLDisplay egl_display_t::getFromNativeDisplay(EGLNativeDisplayType disp) {
     if (uintptr_t(disp) >= NUM_DISPLAYS)
-        return NULL;
+        return nullptr;
 
     return sDisplay[uintptr_t(disp)].getDisplay(disp);
 }
@@ -135,7 +135,7 @@
         disp.dpy = dpy;
         if (dpy == EGL_NO_DISPLAY) {
             loader.close(cnx->dso);
-            cnx->dso = NULL;
+            cnx->dso = nullptr;
         }
     }
 
@@ -148,9 +148,9 @@
         std::unique_lock<std::mutex> _l(refLock);
         refs++;
         if (refs > 1) {
-            if (major != NULL)
+            if (major != nullptr)
                 *major = VERSION_MAJOR;
-            if (minor != NULL)
+            if (minor != nullptr)
                 *minor = VERSION_MINOR;
             while(!eglIsInitialized) {
                 refCond.wait(_l);
@@ -240,12 +240,6 @@
             if (len) {
                 // NOTE: we could avoid the copy if we had strnstr.
                 const std::string ext(start, len);
-                // Temporary hack: Adreno 530 driver exposes this extension under the draft
-                // KHR name, but during Khronos review it was decided to demote it to EXT.
-                if (ext == "EGL_EXT_image_gl_colorspace" &&
-                    findExtension(disp.queryString.extensions, "EGL_KHR_image_gl_colorspace")) {
-                    mExtensionString.append("EGL_EXT_image_gl_colorspace ");
-                }
                 if (findExtension(disp.queryString.extensions, ext.c_str(), len)) {
                     mExtensionString.append(ext + " ");
                 }
@@ -268,9 +262,9 @@
             traceGpuCompletion = true;
         }
 
-        if (major != NULL)
+        if (major != nullptr)
             *major = VERSION_MAJOR;
-        if (minor != NULL)
+        if (minor != nullptr)
             *minor = VERSION_MINOR;
     }
 
@@ -361,8 +355,8 @@
     // by construction, these are either 0 or valid (possibly terminated)
     // it should be impossible for these to be invalid
     ContextRef _cur_c(cur_c);
-    SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
-    SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
+    SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : nullptr);
+    SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : nullptr);
 
     { // scope for the lock
         std::lock_guard<std::mutex> _l(lock);
@@ -387,8 +381,8 @@
     // by construction, these are either 0 or valid (possibly terminated)
     // it should be impossible for these to be invalid
     ContextRef _cur_c(cur_c);
-    SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : NULL);
-    SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : NULL);
+    SurfaceRef _cur_r(cur_c ? get_surface(cur_c->read) : nullptr);
+    SurfaceRef _cur_d(cur_c ? get_surface(cur_c->draw) : nullptr);
 
     { // scope for the lock
         std::lock_guard<std::mutex> _l(lock);
diff --git a/opengl/libs/EGL/egl_display.h b/opengl/libs/EGL/egl_display.h
index 79a9f08..f764028 100644
--- a/opengl/libs/EGL/egl_display.h
+++ b/opengl/libs/EGL/egl_display.h
@@ -160,7 +160,7 @@
     const egl_display_t* get() const { return mDpy; }
           egl_display_t* get()       { return mDpy; }
 
-    operator bool() const { return mDpy != NULL; }
+    operator bool() const { return mDpy != nullptr; }
 
 private:
     egl_display_t* mDpy;
diff --git a/opengl/libs/EGL/egl_object.cpp b/opengl/libs/EGL/egl_object.cpp
index f879254..ff4fe2d 100644
--- a/opengl/libs/EGL/egl_object.cpp
+++ b/opengl/libs/EGL/egl_object.cpp
@@ -81,14 +81,14 @@
 }
 
 egl_surface_t::~egl_surface_t() {
-    if (win != NULL) {
+    if (win != nullptr) {
         disconnect();
         win->decStrong(this);
     }
 }
 
 void egl_surface_t::disconnect() {
-    if (win != NULL && connected) {
+    if (win != nullptr && connected) {
         native_window_set_buffers_format(win, 0);
         if (native_window_api_disconnect(win, NATIVE_WINDOW_API_EGL)) {
             ALOGW("EGLNativeWindowType %p disconnect failed", win);
@@ -281,12 +281,12 @@
 egl_context_t::egl_context_t(EGLDisplay dpy, EGLContext context, EGLConfig config,
         egl_connection_t const* cnx, int version) :
     egl_object_t(get_display_nowake(dpy)), dpy(dpy), context(context),
-            config(config), read(0), draw(0), cnx(cnx), version(version) {
+            config(config), read(nullptr), draw(nullptr), cnx(cnx), version(version) {
 }
 
 void egl_context_t::onLooseCurrent() {
-    read = NULL;
-    draw = NULL;
+    read = nullptr;
+    draw = nullptr;
 }
 
 void egl_context_t::onMakeCurrent(EGLSurface draw, EGLSurface read) {
diff --git a/opengl/libs/EGL/egl_object.h b/opengl/libs/EGL/egl_object.h
index 4e1de5c..fb2bdf4 100644
--- a/opengl/libs/EGL/egl_object.h
+++ b/opengl/libs/EGL/egl_object.h
@@ -67,7 +67,7 @@
     public:
         ~LocalRef();
         explicit LocalRef(egl_object_t* rhs);
-        explicit LocalRef(egl_display_t const* display, T o) : ref(0) {
+        explicit LocalRef(egl_display_t const* display, T o) : ref(nullptr) {
             egl_object_t* native = reinterpret_cast<N*>(o);
             if (o && egl_object_t::get(display, native)) {
                 ref = native;
diff --git a/opengl/libs/EGL/egl_tls.cpp b/opengl/libs/EGL/egl_tls.cpp
index 8508c5f..b57c357 100644
--- a/opengl/libs/EGL/egl_tls.cpp
+++ b/opengl/libs/EGL/egl_tls.cpp
@@ -28,7 +28,7 @@
 pthread_once_t egl_tls_t::sOnceKey = PTHREAD_ONCE_INIT;
 
 egl_tls_t::egl_tls_t()
-    : error(EGL_SUCCESS), ctx(0), logCallWithNoContext(true) {
+    : error(EGL_SUCCESS), ctx(nullptr), logCallWithNoContext(true) {
 }
 
 const char *egl_tls_t::egl_strerror(EGLint err) {
@@ -55,13 +55,38 @@
 void egl_tls_t::validateTLSKey()
 {
     struct TlsKeyInitializer {
-        static void create() {
-            pthread_key_create(&sKey, (void (*)(void*))&eglReleaseThread);
-        }
+        static void create() { pthread_key_create(&sKey, destructTLSData); }
     };
     pthread_once(&sOnceKey, TlsKeyInitializer::create);
 }
 
+void egl_tls_t::destructTLSData(void* data) {
+    egl_tls_t* tls = static_cast<egl_tls_t*>(data);
+    if (!tls) return;
+
+    // Several things in the call tree of eglReleaseThread expect to be able to get the current
+    // thread state directly from TLS. That's a problem because Bionic has already cleared our
+    // TLS pointer before calling this function (pthread_getspecific(sKey) will return nullptr).
+    // Instead the data is passed as our parameter.
+    //
+    // Ideally we'd refactor this so we have thin wrappers that retrieve thread state from TLS and
+    // then pass it as a parameter (or 'this' pointer) to functions that do the real work without
+    // touching TLS. Then from here we could just call those implementation functions with the the
+    // TLS data we just received as a parameter.
+    //
+    // But that's a fairly invasive refactoring, so to do this robustly in the short term we just
+    // put the data *back* in TLS and call the top-level eglReleaseThread. It and it's call tree
+    // will retrieve the value from TLS, and then finally clear the TLS data. Bionic explicitly
+    // tolerates re-setting the value that it's currently trying to destruct (see
+    // pthread_key_clean_all()). Even if we forgot to clear the restored TLS data, bionic would
+    // call the destructor again, but eventually gives up and just leaks the data rather than
+    // enter an infinite loop.
+    pthread_setspecific(sKey, tls);
+    eglReleaseThread();
+    ALOGE_IF(pthread_getspecific(sKey) != nullptr,
+             "EGL TLS data still exists after eglReleaseThread");
+}
+
 void egl_tls_t::setErrorEtcImpl(
         const char* caller, int line, EGLint error, bool quiet) {
     validateTLSKey();
@@ -92,7 +117,7 @@
 
 egl_tls_t* egl_tls_t::getTLS() {
     egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey);
-    if (tls == 0) {
+    if (tls == nullptr) {
         tls = new egl_tls_t;
         pthread_setspecific(sKey, tls);
     }
@@ -103,7 +128,7 @@
     if (sKey != TLS_KEY_NOT_INITIALIZED) {
         egl_tls_t* tls = (egl_tls_t*)pthread_getspecific(sKey);
         if (tls) {
-            pthread_setspecific(sKey, 0);
+            pthread_setspecific(sKey, nullptr);
             delete tls;
         }
     }
diff --git a/opengl/libs/EGL/egl_tls.h b/opengl/libs/EGL/egl_tls.h
index 9feae68..86a375c 100644
--- a/opengl/libs/EGL/egl_tls.h
+++ b/opengl/libs/EGL/egl_tls.h
@@ -38,6 +38,7 @@
 
     egl_tls_t();
     static void validateTLSKey();
+    static void destructTLSData(void* data);
     static void setErrorEtcImpl(
             const char* caller, int line, EGLint error, bool quiet);
 
diff --git a/opengl/libs/EGL/egldefs.h b/opengl/libs/EGL/egldefs.h
index 9858276..299d8f7 100644
--- a/opengl/libs/EGL/egldefs.h
+++ b/opengl/libs/EGL/egldefs.h
@@ -37,7 +37,7 @@
         GLESv2_INDEX = 1
     };
 
-    inline egl_connection_t() : dso(0) { }
+    inline egl_connection_t() : dso(nullptr) { }
     void *              dso;
     gl_hooks_t *        hooks[2];
     EGLint              major;
diff --git a/opengl/libs/tools/genfiles b/opengl/libs/tools/genfiles
deleted file mode 100755
index feef318..0000000
--- a/opengl/libs/tools/genfiles
+++ /dev/null
@@ -1,50 +0,0 @@
-#! /bin/sh
-#
-# Copyright (C) 2008 Google Inc.
-#
-# 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.
-
-# Force a specific locale for sorting to avoid irrelevant differences
-# in the generated files that could hide real differences.
-export LC_ALL=POSIX
-
-./glapigen ../../include/GLES/gl.h      > ../GLES_CM/gl_api.in
-./glapigen ../../include/GLES/glext.h   > ../GLES_CM/glext_api.in
-./glapigen ../../include/GLES3/gl3.h    > ../GLES2/gl2_api.in
-./glapigen ../../include/GLES2/gl2ext.h > ../GLES2/gl2ext_api.in
-
-./glentrygen ../../include/GLES/gl.h      > /tmp/gl_entries.in
-./glentrygen ../../include/GLES/glext.h   > /tmp/glext_entries.in
-./glentrygen ../../include/GLES3/gl3.h    > /tmp/gl2_entries.in
-./glentrygen ../../include/GLES2/gl2ext.h > /tmp/gl2ext_entries.in
-
-# The awk command removes lines with the same function name as an earlier
-# line, even if the rest of the line differs. Although signatures of
-# functions with the same name should be the same, the different versions
-# have some irrelevant whitespace and parameter name differences.
-cat /tmp/gl_entries.in \
-    /tmp/glext_entries.in \
-    /tmp/gl2_entries.in \
-    /tmp/gl2ext_entries.in \
-        | sort -t, -k2 \
-        | awk -F, '!_[$2]++' \
-            > ../entries.in
-
-cat ../../include/GLES/gl.h \
-    ../../include/GLES/glext.h \
-    ../../include/GLES2/gl2ext.h \
-    ../../include/GLES3/gl3.h \
-        | ./glenumsgen \
-        | sort \
-        > ../enums.in
-
diff --git a/opengl/libs/tools/glapigen b/opengl/libs/tools/glapigen
deleted file mode 100755
index 4d8334f..0000000
--- a/opengl/libs/tools/glapigen
+++ /dev/null
@@ -1,76 +0,0 @@
-#! /usr/bin/perl
-#
-# Copyright (C) 2008 Google Inc.
-#
-# 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.
-
-use strict;
-
-sub rtrim($)
-{
-    my $string = shift;
-    $string =~ s/\s+$//;
-    return $string;
-}
-
-while (my $line = <>) {
-  next if $line =~ /^\//;
-  next if $line =~ /^#/;
-  next if $line =~ /^\s*$/;
-  if ($line !~ /^GL_API(CALL)?\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
-    next;
-  }
-  my $type = rtrim($2);
-  my $name = $3;
-  my $args = $4;
-
-  #printf("%s", $line);
-  
-  my $prefix = "";
-  if ($name eq "glGetString") {
-    $prefix = "__";
-  }
-  
-  printf("%s API_ENTRY(%s%s)(%s)", $type, $prefix, $name, $args);
-  
-  printf(" {\n");
-  if ($type eq "void") {
-    printf("    CALL_GL_API(%s", $name);
-  } else {
-    printf("    CALL_GL_API_RETURN(%s", $name);
-  }
-  my @args = split ',', $args;
-  my $len = scalar(@args);
-  for (my $num = 0; $num < $len; $num++) {
-    if ($args[$num] ne "void") {
-      print ", ";
-      #
-      # extract the name from the parameter
-      # type name
-      # const type *name
-      # type *name
-      # type name[4]
-      #
-      if ($args[$num] =~ /(\S+\s)+\**\s*([\w]+)/) {
-        printf("%s", $2);
-      }
-    }
-  }
-  printf(");\n");
-  printf("}\n");
-}
-
-
-
-
-
diff --git a/opengl/libs/tools/glentrygen b/opengl/libs/tools/glentrygen
deleted file mode 100755
index 170f041..0000000
--- a/opengl/libs/tools/glentrygen
+++ /dev/null
@@ -1,38 +0,0 @@
-#! /usr/bin/perl
-#
-# Copyright (C) 2008 Google Inc.
-#
-# 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.
-
-use strict;
-
-sub rtrim($)
-{
-    my $string = shift;
-    $string =~ s/\s+$//;
-    return $string;
-}
-
-while (my $line = <>) {
-  next if $line =~ /^\//;
-  next if $line =~ /^#/;
-  next if $line =~ /^\s*$/;
-  if ($line !~ /^GL_API(CALL)?\s+(.+)\s+GL_APIENTRY\s+([\w]+)\s*\(([^\)]+)\);/) {
-    next;
-  }
-  my $type = rtrim($2);
-  my $name = $3;
-  my $args = $4;
-
-  printf("GL_ENTRY(%s, %s, %s)\n", $type, $name, $args);
-}
diff --git a/opengl/libs/tools/glenumsgen b/opengl/libs/tools/glenumsgen
deleted file mode 100755
index 2ae5fbf..0000000
--- a/opengl/libs/tools/glenumsgen
+++ /dev/null
@@ -1,38 +0,0 @@
-#! /usr/bin/perl
-#
-# Copyright (C) 2010 Google Inc.
-#
-# 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.
-
-use strict;
-
-my %enumHash = ();
-
-while (my $line = <STDIN>) {
-  next if $line =~ /^\//;
-  # Skip bitfield definitions.
-  next if $line =~ /_BIT(\d+_|\s+)/;
-  if ($line !~ /^#define\s+(\S+)\s+(0x\S+)/) {
-    next;
-  }
-  my $enumName = $1;
-  my $enumValue = $2;
-  next if exists($enumHash { $enumValue });
-  $enumHash { $enumValue } = $enumName;
-  printf("GL_ENUM(%s,%s)\n", $enumValue, $enumName);
-}
-
-
-
-
-
diff --git a/opengl/specs/README b/opengl/specs/README
index fdafb1b..6d597d5 100644
--- a/opengl/specs/README
+++ b/opengl/specs/README
@@ -19,10 +19,7 @@
 0x3145               EGL_SYNC_NATIVE_FENCE_FD_ANDROID (EGL_ANDROID_native_fence_sync)
 0x3146               EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID (EGL_ANDROID_native_fence_sync)
 0x3147               EGL_FRAMEBUFFER_TARGET_ANDROID (EGL_ANDROID_framebuffer_target)
-0x3148               EGL_IMAGE_CROP_LEFT_ANDROID (EGL_ANDROID_image_crop)
-0x3149               EGL_IMAGE_CROP_TOP_ANDROID (EGL_ANDROID_image_crop)
-0x314A               EGL_IMAGE_CROP_RIGHT_ANDROID (EGL_ANDROID_image_crop)
-0x314B               EGL_IMAGE_CROP_BOTTOM_ANDROID (EGL_ANDROID_image_crop)
+0x3148 - 0x314B      previously used by the undocumented, deprecated extension EGL_ANDROID_image_crop
 0x314C               EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID (EGL_ANDROID_front_buffer_auto_refresh)
 0x314D               EGL_GL_COLORSPACE_DEFAULT_EXT (EGL_EXT_image_gl_colorspace)
 0x314E - 0x314F      (unused)
diff --git a/opengl/tests/lib/WindowSurface.cpp b/opengl/tests/lib/WindowSurface.cpp
index 2b76279..b06422a 100644
--- a/opengl/tests/lib/WindowSurface.cpp
+++ b/opengl/tests/lib/WindowSurface.cpp
@@ -57,7 +57,7 @@
     sp<SurfaceControl> sc = surfaceComposerClient->createSurface(
             String8("Benchmark"), width, height,
             PIXEL_FORMAT_RGBX_8888, ISurfaceComposerClient::eOpaque);
-    if (sc == NULL || !sc->isValid()) {
+    if (sc == nullptr || !sc->isValid()) {
         fprintf(stderr, "Failed to create SurfaceControl\n");
         return;
     }
diff --git a/opengl/tests/lib/glTestLib.cpp b/opengl/tests/lib/glTestLib.cpp
index 213dffd..290d7a0 100644
--- a/opengl/tests/lib/glTestLib.cpp
+++ b/opengl/tests/lib/glTestLib.cpp
@@ -37,7 +37,7 @@
 {
     const char *v = (const char *) glGetString(s);
 
-    if (v == NULL) {
+    if (v == nullptr) {
         testPrintI("GL %s unknown", name);
     } else {
         testPrintI("GL %s = %s", name, v);
diff --git a/opengl/tests/lib/include/EGLUtils.h b/opengl/tests/lib/include/EGLUtils.h
index 9dc6bcf..eb9571d 100644
--- a/opengl/tests/lib/include/EGLUtils.h
+++ b/opengl/tests/lib/include/EGLUtils.h
@@ -100,11 +100,11 @@
     if (!attrs)
         return BAD_VALUE;
 
-    if (outConfig == NULL)
+    if (outConfig == nullptr)
         return BAD_VALUE;
 
     // Get all the "potential match" configs...
-    if (eglGetConfigs(dpy, NULL, 0, &numConfigs) == EGL_FALSE)
+    if (eglGetConfigs(dpy, nullptr, 0, &numConfigs) == EGL_FALSE)
         return BAD_VALUE;
 
     std::vector<EGLConfig> configs(numConfigs);
@@ -113,7 +113,7 @@
     }
 
     int i;
-    EGLConfig config = NULL;
+    EGLConfig config = nullptr;
     for (i=0 ; i<n ; i++) {
         EGLint nativeVisualId = 0;
         eglGetConfigAttrib(dpy, configs[i], EGL_NATIVE_VISUAL_ID, &nativeVisualId);
@@ -243,7 +243,7 @@
 
 bool EGLUtils::printEGLConfigurations(EGLDisplay dpy, String8& msg) {
     EGLint numConfig = 0;
-    EGLint returnVal = eglGetConfigs(dpy, NULL, 0, &numConfig);
+    EGLint returnVal = eglGetConfigs(dpy, nullptr, 0, &numConfig);
     msg.append(checkEglError("eglGetConfigs", returnVal));
     if (!returnVal) {
         return false;
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index a9e5a43..45efb9f 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -15,6 +15,8 @@
 cc_library_shared {
     name: "libinputflinger",
 
+    cpp_std: "c++17",
+
     srcs: [
         "EventHub.cpp",
         "InputApplication.cpp",
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 4d9a2a0..77a474f 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -143,9 +143,9 @@
 
 EventHub::Device::Device(int fd, int32_t id, const String8& path,
         const InputDeviceIdentifier& identifier) :
-        next(NULL),
+        next(nullptr),
         fd(fd), id(id), path(path), identifier(identifier),
-        classes(0), configuration(NULL), virtualKeyMap(NULL),
+        classes(0), configuration(nullptr), virtualKeyMap(nullptr),
         ffEffectPlaying(false), ffEffectId(-1), controllerNumber(0),
         timestampOverrideSec(0), timestampOverrideUsec(0), enabled(true),
         isVirtual(fd < 0) {
@@ -200,7 +200,7 @@
 
 EventHub::EventHub(void) :
         mBuiltInKeyboardId(NO_BUILT_IN_KEYBOARD), mNextDeviceId(1), mControllerNumbers(),
-        mOpeningDevices(0), mClosingDevices(0),
+        mOpeningDevices(nullptr), mClosingDevices(nullptr),
         mNeedToSendFinishedDeviceScan(false),
         mNeedToReopenDevices(false), mNeedToScanDevices(true),
         mPendingEventCount(0), mPendingEventIndex(0), mPendingINotify(false) {
@@ -267,21 +267,21 @@
 InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device == NULL) return InputDeviceIdentifier();
+    if (device == nullptr) return InputDeviceIdentifier();
     return device->identifier;
 }
 
 uint32_t EventHub::getDeviceClasses(int32_t deviceId) const {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device == NULL) return 0;
+    if (device == nullptr) return 0;
     return device->classes;
 }
 
 int32_t EventHub::getDeviceControllerNumber(int32_t deviceId) const {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device == NULL) return 0;
+    if (device == nullptr) return 0;
     return device->controllerNumber;
 }
 
@@ -465,7 +465,7 @@
     if (device) {
         // Check the key character map first.
         sp<KeyCharacterMap> kcm = device->getKeyCharacterMap();
-        if (kcm != NULL) {
+        if (kcm != nullptr) {
             if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
                 *outFlags = 0;
                 status = NO_ERROR;
@@ -481,7 +481,7 @@
         }
 
         if (status == NO_ERROR) {
-            if (kcm != NULL) {
+            if (kcm != nullptr) {
                 kcm->tryRemapKey(*outKeycode, metaState, outKeycode, outMetaState);
             } else {
                 *outMetaState = metaState;
@@ -581,7 +581,7 @@
     if (device) {
         return device->getKeyCharacterMap();
     }
-    return NULL;
+    return nullptr;
 }
 
 bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId,
@@ -641,7 +641,7 @@
     if (identifier.uniqueId.isEmpty()) {
         // If it didn't have a unique id check for conflicts and enforce
         // uniqueness if necessary.
-        while(getDeviceByDescriptorLocked(identifier.descriptor) != NULL) {
+        while(getDeviceByDescriptorLocked(identifier.descriptor) != nullptr) {
             identifier.nonce++;
             rawDescriptor = generateDescriptor(identifier);
         }
@@ -714,7 +714,7 @@
             return device;
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 EventHub::Device* EventHub::getDeviceLocked(int32_t deviceId) const {
@@ -732,7 +732,7 @@
             return device;
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
@@ -782,7 +782,7 @@
             mNeedToSendFinishedDeviceScan = true;
         }
 
-        while (mOpeningDevices != NULL) {
+        while (mOpeningDevices != nullptr) {
             Device* device = mOpeningDevices;
             ALOGV("Reporting device opened: id=%d, name=%s\n",
                  device->id, device->path.string());
@@ -1099,7 +1099,7 @@
 
 status_t EventHub::unregisterDeviceFromEpollLocked(Device* device) {
     if (device->hasValidFd()) {
-        if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, NULL)) {
+        if (epoll_ctl(mEpollFd, EPOLL_CTL_DEL, device->fd, nullptr)) {
             ALOGW("Could not remove device fd from epoll instance.  errno=%d", errno);
             return -errno;
         }
@@ -1423,7 +1423,7 @@
 bool EventHub::isDeviceEnabled(int32_t deviceId) {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device == NULL) {
+    if (device == nullptr) {
         ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
         return false;
     }
@@ -1433,7 +1433,7 @@
 status_t EventHub::enableDevice(int32_t deviceId) {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device == NULL) {
+    if (device == nullptr) {
         ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
         return BAD_VALUE;
     }
@@ -1455,7 +1455,7 @@
 status_t EventHub::disableDevice(int32_t deviceId) {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
-    if (device == NULL) {
+    if (device == nullptr) {
         ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
         return BAD_VALUE;
     }
@@ -1634,9 +1634,9 @@
     device->close();
 
     // Unlink for opening devices list if it is present.
-    Device* pred = NULL;
+    Device* pred = nullptr;
     bool found = false;
-    for (Device* entry = mOpeningDevices; entry != NULL; ) {
+    for (Device* entry = mOpeningDevices; entry != nullptr; ) {
         if (entry == device) {
             found = true;
             break;
@@ -1712,7 +1712,7 @@
     DIR *dir;
     struct dirent *de;
     dir = opendir(dirname);
-    if(dir == NULL)
+    if(dir == nullptr)
         return -1;
     strcpy(devname, dirname);
     filename = devname + strlen(devname);
@@ -1773,7 +1773,7 @@
             dump += StringPrintf(INDENT3 "ConfigurationFile: %s\n",
                     device->configurationFile.string());
             dump += StringPrintf(INDENT3 "HaveKeyboardLayoutOverlay: %s\n",
-                    toString(device->overlayKeyMap != NULL));
+                    toString(device->overlayKeyMap != nullptr));
         }
     } // release lock
 }
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index 66bc294..dfe3def 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -385,7 +385,7 @@
         const bool isVirtual; // set if fd < 0 is passed to constructor
 
         const sp<KeyCharacterMap>& getKeyCharacterMap() const {
-            if (combinedKeyMap != NULL) {
+            if (combinedKeyMap != nullptr) {
                 return combinedKeyMap;
             }
             return keyMap.keyCharacterMap;
diff --git a/services/inputflinger/InputApplication.cpp b/services/inputflinger/InputApplication.cpp
index 9e90631..c56dfe6 100644
--- a/services/inputflinger/InputApplication.cpp
+++ b/services/inputflinger/InputApplication.cpp
@@ -25,7 +25,7 @@
 // --- InputApplicationHandle ---
 
 InputApplicationHandle::InputApplicationHandle() :
-    mInfo(NULL) {
+    mInfo(nullptr) {
 }
 
 InputApplicationHandle::~InputApplicationHandle() {
@@ -35,7 +35,7 @@
 void InputApplicationHandle::releaseInfo() {
     if (mInfo) {
         delete mInfo;
-        mInfo = NULL;
+        mInfo = nullptr;
     }
 }
 
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 9a449fa..c805805 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -240,14 +240,14 @@
 
 InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy) :
     mPolicy(policy),
-    mPendingEvent(NULL), mLastDropReason(DROP_REASON_NOT_DROPPED),
+    mPendingEvent(nullptr), mLastDropReason(DROP_REASON_NOT_DROPPED),
     mAppSwitchSawKeyDown(false), mAppSwitchDueTime(LONG_LONG_MAX),
-    mNextUnblockedEvent(NULL),
+    mNextUnblockedEvent(nullptr),
     mDispatchEnabled(false), mDispatchFrozen(false), mInputFilterEnabled(false),
     mInputTargetWaitCause(INPUT_TARGET_WAIT_CAUSE_NONE) {
     mLooper = new Looper(false);
 
-    mKeyRepeatState.lastKeyEntry = NULL;
+    mKeyRepeatState.lastKeyEntry = nullptr;
 
     policy->getDispatcherConfiguration(&mConfig);
 }
@@ -360,7 +360,7 @@
 
     // Now we have an event to dispatch.
     // All events are eventually dequeued and processed this way, even if we intend to drop them.
-    ALOG_ASSERT(mPendingEvent != NULL);
+    ALOG_ASSERT(mPendingEvent != nullptr);
     bool done = false;
     DropReason dropReason = DROP_REASON_NOT_DROPPED;
     if (!(mPendingEvent->policyFlags & POLICY_FLAG_PASS_TO_USER)) {
@@ -370,7 +370,7 @@
     }
 
     if (mNextUnblockedEvent == mPendingEvent) {
-        mNextUnblockedEvent = NULL;
+        mNextUnblockedEvent = nullptr;
     }
 
     switch (mPendingEvent->type) {
@@ -481,14 +481,14 @@
         if (motionEntry->action == AMOTION_EVENT_ACTION_DOWN
                 && (motionEntry->source & AINPUT_SOURCE_CLASS_POINTER)
                 && mInputTargetWaitCause == INPUT_TARGET_WAIT_CAUSE_APPLICATION_NOT_READY
-                && mInputTargetWaitApplicationHandle != NULL) {
+                && mInputTargetWaitApplicationHandle != nullptr) {
             int32_t displayId = motionEntry->displayId;
             int32_t x = int32_t(motionEntry->pointerCoords[0].
                     getAxisValue(AMOTION_EVENT_AXIS_X));
             int32_t y = int32_t(motionEntry->pointerCoords[0].
                     getAxisValue(AMOTION_EVENT_AXIS_Y));
             sp<InputWindowHandle> touchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y);
-            if (touchedWindowHandle != NULL
+            if (touchedWindowHandle != nullptr
                     && touchedWindowHandle->inputApplicationHandle
                             != mInputTargetWaitApplicationHandle) {
                 // User touched a different application than the one we are waiting on.
@@ -534,7 +534,7 @@
             }
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 void InputDispatcher::dropInboundEventLocked(EventEntry* entry, DropReason dropReason) {
@@ -663,7 +663,7 @@
     if (mPendingEvent) {
         resetANRTimeoutsLocked();
         releaseInboundEventLocked(mPendingEvent);
-        mPendingEvent = NULL;
+        mPendingEvent = nullptr;
     }
 }
 
@@ -676,7 +676,7 @@
         setInjectionResultLocked(entry, INPUT_EVENT_INJECTION_FAILED);
     }
     if (entry == mNextUnblockedEvent) {
-        mNextUnblockedEvent = NULL;
+        mNextUnblockedEvent = nullptr;
     }
     addRecentEventLocked(entry);
     entry->release();
@@ -685,7 +685,7 @@
 void InputDispatcher::resetKeyRepeatLocked() {
     if (mKeyRepeatState.lastKeyEntry) {
         mKeyRepeatState.lastKeyEntry->release();
-        mKeyRepeatState.lastKeyEntry = NULL;
+        mKeyRepeatState.lastKeyEntry = nullptr;
     }
 }
 
@@ -702,7 +702,7 @@
         entry->repeatCount += 1;
     } else {
         KeyEntry* newEntry = new KeyEntry(currentTime,
-                entry->deviceId, entry->source, policyFlags,
+                entry->deviceId, entry->source, entry->displayId, policyFlags,
                 entry->action, entry->flags, entry->keyCode, entry->scanCode,
                 entry->metaState, entry->repeatCount + 1, entry->downTime);
 
@@ -807,7 +807,7 @@
         if (entry->policyFlags & POLICY_FLAG_PASS_TO_USER) {
             CommandEntry* commandEntry = postCommandLocked(
                     & InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible);
-            if (mFocusedWindowHandle != NULL) {
+            if (mFocusedWindowHandle != nullptr) {
                 commandEntry->inputWindowHandle = mFocusedWindowHandle;
             }
             commandEntry->keyEntry = entry;
@@ -851,11 +851,11 @@
 
 void InputDispatcher::logOutboundKeyDetailsLocked(const char* prefix, const KeyEntry* entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
-            "action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, "
-            "repeatCount=%d, downTime=%" PRId64,
+    ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32 ", "
+            "policyFlags=0x%x, action=0x%x, flags=0x%x, keyCode=0x%x, scanCode=0x%x, "
+            "metaState=0x%x, repeatCount=%d, downTime=%" PRId64,
             prefix,
-            entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
+            entry->eventTime, entry->deviceId, entry->source, entry->displayId, entry->policyFlags,
             entry->action, entry->flags, entry->keyCode, entry->scanCode, entry->metaState,
             entry->repeatCount, entry->downTime);
 #endif
@@ -924,12 +924,13 @@
 
 void InputDispatcher::logOutboundMotionDetailsLocked(const char* prefix, const MotionEntry* entry) {
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-    ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
+    ALOGD("%seventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
+            ", policyFlags=0x%x, "
             "action=0x%x, actionButton=0x%x, flags=0x%x, "
             "metaState=0x%x, buttonState=0x%x,"
             "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
             prefix,
-            entry->eventTime, entry->deviceId, entry->source, entry->policyFlags,
+            entry->eventTime, entry->deviceId, entry->source, entry->displayId, entry->policyFlags,
             entry->action, entry->actionButton, entry->flags,
             entry->metaState, entry->buttonState,
             entry->edgeFlags, entry->xPrecision, entry->yPrecision,
@@ -987,7 +988,7 @@
         const sp<InputApplicationHandle>& applicationHandle,
         const sp<InputWindowHandle>& windowHandle,
         nsecs_t* nextWakeupTime, const char* reason) {
-    if (applicationHandle == NULL && windowHandle == NULL) {
+    if (applicationHandle == nullptr && windowHandle == nullptr) {
         if (mInputTargetWaitCause != INPUT_TARGET_WAIT_CAUSE_SYSTEM_NOT_READY) {
 #if DEBUG_FOCUS
             ALOGD("Waiting for system to become ready for input.  Reason: %s", reason);
@@ -1006,9 +1007,9 @@
                     reason);
 #endif
             nsecs_t timeout;
-            if (windowHandle != NULL) {
+            if (windowHandle != nullptr) {
                 timeout = windowHandle->getDispatchingTimeout(DEFAULT_INPUT_DISPATCHING_TIMEOUT);
-            } else if (applicationHandle != NULL) {
+            } else if (applicationHandle != nullptr) {
                 timeout = applicationHandle->getDispatchingTimeout(
                         DEFAULT_INPUT_DISPATCHING_TIMEOUT);
             } else {
@@ -1021,10 +1022,10 @@
             mInputTargetWaitTimeoutExpired = false;
             mInputTargetWaitApplicationHandle.clear();
 
-            if (windowHandle != NULL) {
+            if (windowHandle != nullptr) {
                 mInputTargetWaitApplicationHandle = windowHandle->inputApplicationHandle;
             }
-            if (mInputTargetWaitApplicationHandle == NULL && applicationHandle != NULL) {
+            if (mInputTargetWaitApplicationHandle == nullptr && applicationHandle != nullptr) {
                 mInputTargetWaitApplicationHandle = applicationHandle;
             }
         }
@@ -1067,7 +1068,7 @@
                 sp<Connection> connection = mConnectionsByFd.valueAt(connectionIndex);
                 sp<InputWindowHandle> windowHandle = connection->inputWindowHandle;
 
-                if (windowHandle != NULL) {
+                if (windowHandle != nullptr) {
                     const InputWindowInfo* info = windowHandle->getInfo();
                     if (info) {
                         ssize_t stateIndex = mTouchStatesByDisplay.indexOfKey(info->displayId);
@@ -1113,10 +1114,10 @@
 
     // If there is no currently focused window and no focused application
     // then drop the event.
-    if (mFocusedWindowHandle == NULL) {
-        if (mFocusedApplicationHandle != NULL) {
+    if (mFocusedWindowHandle == nullptr) {
+        if (mFocusedApplicationHandle != nullptr) {
             injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                    mFocusedApplicationHandle, NULL, nextWakeupTime,
+                    mFocusedApplicationHandle, nullptr, nextWakeupTime,
                     "Waiting because no window has focus but there is a "
                     "focused application that may eventually add a window "
                     "when it finishes starting up.");
@@ -1186,7 +1187,7 @@
     // Copy current touch state into mTempTouchState.
     // This state is always reset at the end of this function, so if we don't find state
     // for the specified display then our initial state will be empty.
-    const TouchState* oldState = NULL;
+    const TouchState* oldState = nullptr;
     ssize_t oldStateIndex = mTouchStatesByDisplay.indexOfKey(displayId);
     if (oldStateIndex >= 0) {
         oldState = &mTouchStatesByDisplay.valueAt(oldStateIndex);
@@ -1274,21 +1275,21 @@
         }
 
         // Figure out whether splitting will be allowed for this window.
-        if (newTouchedWindowHandle != NULL
+        if (newTouchedWindowHandle != nullptr
                 && newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
             // New window supports splitting.
             isSplit = true;
         } else if (isSplit) {
             // New window does not support splitting but we have already split events.
             // Ignore the new window.
-            newTouchedWindowHandle = NULL;
+            newTouchedWindowHandle = nullptr;
         }
 
         // Handle the case where we did not find a window.
-        if (newTouchedWindowHandle == NULL) {
+        if (newTouchedWindowHandle == nullptr) {
             // Try to assign the pointer to the first foreground window we find, if there is one.
             newTouchedWindowHandle = mTempTouchState.getFirstForegroundWindowHandle();
-            if (newTouchedWindowHandle == NULL) {
+            if (newTouchedWindowHandle == nullptr) {
                 ALOGI("Dropping event because there is no touchable window at (%d, %d).", x, y);
                 injectionResult = INPUT_EVENT_INJECTION_FAILED;
                 goto Failed;
@@ -1345,7 +1346,7 @@
             sp<InputWindowHandle> newTouchedWindowHandle =
                     findTouchedWindowAtLocked(displayId, x, y);
             if (oldTouchedWindowHandle != newTouchedWindowHandle
-                    && newTouchedWindowHandle != NULL) {
+                    && newTouchedWindowHandle != nullptr) {
 #if DEBUG_FOCUS
                 ALOGD("Touch is slipping out of window %s into window %s.",
                         oldTouchedWindowHandle->getName().c_str(),
@@ -1380,7 +1381,7 @@
 
     if (newHoverWindowHandle != mLastHoverWindowHandle) {
         // Let the previous window know that the hover sequence is over.
-        if (mLastHoverWindowHandle != NULL) {
+        if (mLastHoverWindowHandle != nullptr) {
 #if DEBUG_HOVER
             ALOGD("Sending hover exit event to window %s.",
                     mLastHoverWindowHandle->getName().c_str());
@@ -1390,7 +1391,7 @@
         }
 
         // Let the new window know that the hover sequence is starting.
-        if (newHoverWindowHandle != NULL) {
+        if (newHoverWindowHandle != nullptr) {
 #if DEBUG_HOVER
             ALOGD("Sending hover enter event to window %s.",
                     newHoverWindowHandle->getName().c_str());
@@ -1455,7 +1456,7 @@
                     touchedWindow.windowHandle, entry, "touched");
             if (!reason.empty()) {
                 injectionResult = handleTargetsNotReadyLocked(currentTime, entry,
-                        NULL, touchedWindow.windowHandle, nextWakeupTime, reason.c_str());
+                        nullptr, touchedWindow.windowHandle, nextWakeupTime, reason.c_str());
                 goto Unresponsive;
             }
         }
@@ -1503,7 +1504,7 @@
 Failed:
     // Check injection permission once and for all.
     if (injectionPermission == INJECTION_PERMISSION_UNKNOWN) {
-        if (checkInjectionPermission(NULL, entry->injectionState)) {
+        if (checkInjectionPermission(nullptr, entry->injectionState)) {
             injectionPermission = INJECTION_PERMISSION_GRANTED;
         } else {
             injectionPermission = INJECTION_PERMISSION_DENIED;
@@ -1636,10 +1637,10 @@
 bool InputDispatcher::checkInjectionPermission(const sp<InputWindowHandle>& windowHandle,
         const InjectionState* injectionState) {
     if (injectionState
-            && (windowHandle == NULL
+            && (windowHandle == nullptr
                     || windowHandle->getInfo()->ownerUid != injectionState->injectorUid)
             && !hasInjectionPermission(injectionState->injectorPid, injectionState->injectorUid)) {
-        if (windowHandle != NULL) {
+        if (windowHandle != nullptr) {
             ALOGW("Permission denied: injecting event from pid %d uid %d to window %s "
                     "owned by uid %d",
                     injectionState->injectorPid, injectionState->injectorUid,
@@ -1778,8 +1779,8 @@
 std::string InputDispatcher::getApplicationWindowLabelLocked(
         const sp<InputApplicationHandle>& applicationHandle,
         const sp<InputWindowHandle>& windowHandle) {
-    if (applicationHandle != NULL) {
-        if (windowHandle != NULL) {
+    if (applicationHandle != nullptr) {
+        if (windowHandle != nullptr) {
             std::string label(applicationHandle->getName());
             label += " - ";
             label += windowHandle->getName();
@@ -1787,7 +1788,7 @@
         } else {
             return applicationHandle->getName();
         }
-    } else if (windowHandle != NULL) {
+    } else if (windowHandle != nullptr) {
         return windowHandle->getName();
     } else {
         return "<unknown application or window>";
@@ -1795,7 +1796,7 @@
 }
 
 void InputDispatcher::pokeUserActivityLocked(const EventEntry* eventEntry) {
-    if (mFocusedWindowHandle != NULL) {
+    if (mFocusedWindowHandle != nullptr) {
         const InputWindowInfo* info = mFocusedWindowHandle->getInfo();
         if (info->inputFeatures & InputWindowInfo::INPUT_FEATURE_DISABLE_USER_ACTIVITY) {
 #if DEBUG_DISPATCH_CYCLE
@@ -2017,7 +2018,7 @@
 
             // Publish the key event.
             status = connection->inputPublisher.publishKeyEvent(dispatchEntry->seq,
-                    keyEntry->deviceId, keyEntry->source,
+                    keyEntry->deviceId, keyEntry->source, keyEntry->displayId,
                     dispatchEntry->resolvedAction, dispatchEntry->resolvedFlags,
                     keyEntry->keyCode, keyEntry->scanCode,
                     keyEntry->metaState, keyEntry->repeatCount, keyEntry->downTime,
@@ -2291,7 +2292,7 @@
 
             InputTarget target;
             sp<InputWindowHandle> windowHandle = getWindowHandleLocked(connection->inputChannel);
-            if (windowHandle != NULL) {
+            if (windowHandle != nullptr) {
                 const InputWindowInfo* windowInfo = windowHandle->getInfo();
                 target.xOffset = -windowInfo->frameLeft;
                 target.yOffset = -windowInfo->frameTop;
@@ -2349,7 +2350,7 @@
                 "we expected there to be %d pointers.  This probably means we received "
                 "a broken sequence of pointer ids from the input device.",
                 splitPointerCount, pointerIds.count());
-        return NULL;
+        return nullptr;
     }
 
     int32_t action = originalMotionEntry->action;
@@ -2384,6 +2385,7 @@
             originalMotionEntry->eventTime,
             originalMotionEntry->deviceId,
             originalMotionEntry->source,
+            originalMotionEntry->displayId,
             originalMotionEntry->policyFlags,
             action,
             originalMotionEntry->actionButton,
@@ -2394,7 +2396,6 @@
             originalMotionEntry->xPrecision,
             originalMotionEntry->yPrecision,
             originalMotionEntry->downTime,
-            originalMotionEntry->displayId,
             splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0);
 
     if (originalMotionEntry->injectionState) {
@@ -2423,12 +2424,49 @@
     }
 }
 
+/**
+ * If one of the meta shortcuts is detected, process them here:
+ *     Meta + Backspace -> generate BACK
+ *     Meta + Enter -> generate HOME
+ * This will potentially overwrite keyCode and metaState.
+ */
+void InputDispatcher::accelerateMetaShortcuts(const int32_t deviceId, const int32_t action,
+        int32_t& keyCode, int32_t& metaState) {
+    if (metaState & AMETA_META_ON && action == AKEY_EVENT_ACTION_DOWN) {
+        int32_t newKeyCode = AKEYCODE_UNKNOWN;
+        if (keyCode == AKEYCODE_DEL) {
+            newKeyCode = AKEYCODE_BACK;
+        } else if (keyCode == AKEYCODE_ENTER) {
+            newKeyCode = AKEYCODE_HOME;
+        }
+        if (newKeyCode != AKEYCODE_UNKNOWN) {
+            AutoMutex _l(mLock);
+            struct KeyReplacement replacement = {keyCode, deviceId};
+            mReplacedKeys.add(replacement, newKeyCode);
+            keyCode = newKeyCode;
+            metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
+        }
+    } else if (action == AKEY_EVENT_ACTION_UP) {
+        // In order to maintain a consistent stream of up and down events, check to see if the key
+        // going up is one we've replaced in a down event and haven't yet replaced in an up event,
+        // even if the modifier was released between the down and the up events.
+        AutoMutex _l(mLock);
+        struct KeyReplacement replacement = {keyCode, deviceId};
+        ssize_t index = mReplacedKeys.indexOfKey(replacement);
+        if (index >= 0) {
+            keyCode = mReplacedKeys.valueAt(index);
+            mReplacedKeys.removeItemsAt(index);
+            metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
+        }
+    }
+}
+
 void InputDispatcher::notifyKey(const NotifyKeyArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
     ALOGD("notifyKey - eventTime=%" PRId64
-            ", deviceId=%d, source=0x%x, policyFlags=0x%x, action=0x%x, "
+            ", deviceId=%d, source=0x%x, displayId=%" PRId32 "policyFlags=0x%x, action=0x%x, "
             "flags=0x%x, keyCode=0x%x, scanCode=0x%x, metaState=0x%x, downTime=%" PRId64,
-            args->eventTime, args->deviceId, args->source, args->policyFlags,
+            args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
             args->action, args->flags, args->keyCode, args->scanCode,
             args->metaState, args->downTime);
 #endif
@@ -2450,36 +2488,10 @@
     policyFlags |= POLICY_FLAG_TRUSTED;
 
     int32_t keyCode = args->keyCode;
-    if (metaState & AMETA_META_ON && args->action == AKEY_EVENT_ACTION_DOWN) {
-        int32_t newKeyCode = AKEYCODE_UNKNOWN;
-        if (keyCode == AKEYCODE_DEL) {
-            newKeyCode = AKEYCODE_BACK;
-        } else if (keyCode == AKEYCODE_ENTER) {
-            newKeyCode = AKEYCODE_HOME;
-        }
-        if (newKeyCode != AKEYCODE_UNKNOWN) {
-            AutoMutex _l(mLock);
-            struct KeyReplacement replacement = {keyCode, args->deviceId};
-            mReplacedKeys.add(replacement, newKeyCode);
-            keyCode = newKeyCode;
-            metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
-        }
-    } else if (args->action == AKEY_EVENT_ACTION_UP) {
-        // In order to maintain a consistent stream of up and down events, check to see if the key
-        // going up is one we've replaced in a down event and haven't yet replaced in an up event,
-        // even if the modifier was released between the down and the up events.
-        AutoMutex _l(mLock);
-        struct KeyReplacement replacement = {keyCode, args->deviceId};
-        ssize_t index = mReplacedKeys.indexOfKey(replacement);
-        if (index >= 0) {
-            keyCode = mReplacedKeys.valueAt(index);
-            mReplacedKeys.removeItemsAt(index);
-            metaState &= ~(AMETA_META_ON | AMETA_META_LEFT_ON | AMETA_META_RIGHT_ON);
-        }
-    }
+    accelerateMetaShortcuts(args->deviceId, args->action, keyCode, metaState);
 
     KeyEvent event;
-    event.initialize(args->deviceId, args->source, args->action,
+    event.initialize(args->deviceId, args->source, args->displayId, args->action,
             flags, keyCode, args->scanCode, metaState, 0,
             args->downTime, args->eventTime);
 
@@ -2507,7 +2519,7 @@
 
         int32_t repeatCount = 0;
         KeyEntry* newEntry = new KeyEntry(args->eventTime,
-                args->deviceId, args->source, policyFlags,
+                args->deviceId, args->source, args->displayId, policyFlags,
                 args->action, flags, keyCode, args->scanCode,
                 metaState, repeatCount, args->downTime);
 
@@ -2526,10 +2538,11 @@
 
 void InputDispatcher::notifyMotion(const NotifyMotionArgs* args) {
 #if DEBUG_INBOUND_EVENT_DETAILS
-    ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, policyFlags=0x%x, "
+    ALOGD("notifyMotion - eventTime=%" PRId64 ", deviceId=%d, source=0x%x, displayId=%" PRId32
+            ", policyFlags=0x%x, "
             "action=0x%x, actionButton=0x%x, flags=0x%x, metaState=0x%x, buttonState=0x%x,"
             "edgeFlags=0x%x, xPrecision=%f, yPrecision=%f, downTime=%" PRId64,
-            args->eventTime, args->deviceId, args->source, args->policyFlags,
+            args->eventTime, args->deviceId, args->source, args->displayId, args->policyFlags,
             args->action, args->actionButton, args->flags, args->metaState, args->buttonState,
             args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime);
     for (uint32_t i = 0; i < args->pointerCount; i++) {
@@ -2573,7 +2586,8 @@
             mLock.unlock();
 
             MotionEvent event;
-            event.initialize(args->deviceId, args->source, args->action, args->actionButton,
+            event.initialize(args->deviceId, args->source, args->displayId,
+                    args->action, args->actionButton,
                     args->flags, args->edgeFlags, args->metaState, args->buttonState,
                     0, 0, args->xPrecision, args->yPrecision,
                     args->downTime, args->eventTime,
@@ -2589,11 +2603,10 @@
 
         // Just enqueue a new motion event.
         MotionEntry* newEntry = new MotionEntry(args->eventTime,
-                args->deviceId, args->source, policyFlags,
+                args->deviceId, args->source, args->displayId, policyFlags,
                 args->action, args->actionButton, args->flags,
                 args->metaState, args->buttonState,
                 args->edgeFlags, args->xPrecision, args->yPrecision, args->downTime,
-                args->displayId,
                 args->pointerCount, args->pointerProperties, args->pointerCoords, 0, 0);
 
         needWake = enqueueInboundEventLocked(newEntry);
@@ -2642,14 +2655,13 @@
     }
 }
 
-int32_t InputDispatcher::injectInputEvent(const InputEvent* event, int32_t displayId,
+int32_t InputDispatcher::injectInputEvent(const InputEvent* event,
         int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
         uint32_t policyFlags) {
 #if DEBUG_INBOUND_EVENT_DETAILS
     ALOGD("injectInputEvent - eventType=%d, injectorPid=%d, injectorUid=%d, "
-            "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x, displayId=%d",
-            event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags,
-            displayId);
+            "syncMode=%d, timeoutMillis=%d, policyFlags=0x%08x",
+            event->getType(), injectorPid, injectorUid, syncMode, timeoutMillis, policyFlags);
 #endif
 
     nsecs_t endTime = now() + milliseconds_to_nanoseconds(timeoutMillis);
@@ -2663,20 +2675,29 @@
     EventEntry* lastInjectedEntry;
     switch (event->getType()) {
     case AINPUT_EVENT_TYPE_KEY: {
-        const KeyEvent* keyEvent = static_cast<const KeyEvent*>(event);
-        int32_t action = keyEvent->getAction();
+        KeyEvent keyEvent;
+        keyEvent.initialize(*static_cast<const KeyEvent*>(event));
+        int32_t action = keyEvent.getAction();
         if (! validateKeyEvent(action)) {
             return INPUT_EVENT_INJECTION_FAILED;
         }
 
-        int32_t flags = keyEvent->getFlags();
+        int32_t flags = keyEvent.getFlags();
+        int32_t keyCode = keyEvent.getKeyCode();
+        int32_t metaState = keyEvent.getMetaState();
+        accelerateMetaShortcuts(keyEvent.getDeviceId(), action,
+                /*byref*/ keyCode, /*byref*/ metaState);
+        keyEvent.initialize(keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(),
+            action, flags, keyCode, keyEvent.getScanCode(), metaState, 0,
+            keyEvent.getDownTime(), keyEvent.getEventTime());
+
         if (flags & AKEY_EVENT_FLAG_VIRTUAL_HARD_KEY) {
             policyFlags |= POLICY_FLAG_VIRTUAL;
         }
 
         if (!(policyFlags & POLICY_FLAG_FILTERED)) {
             android::base::Timer t;
-            mPolicy->interceptKeyBeforeQueueing(keyEvent, /*byref*/ policyFlags);
+            mPolicy->interceptKeyBeforeQueueing(&keyEvent, /*byref*/ policyFlags);
             if (t.duration() > SLOW_INTERCEPTION_THRESHOLD) {
                 ALOGW("Excessive delay in interceptKeyBeforeQueueing; took %s ms",
                         std::to_string(t.duration().count()).c_str());
@@ -2684,11 +2705,11 @@
         }
 
         mLock.lock();
-        firstInjectedEntry = new KeyEntry(keyEvent->getEventTime(),
-                keyEvent->getDeviceId(), keyEvent->getSource(),
+        firstInjectedEntry = new KeyEntry(keyEvent.getEventTime(),
+                keyEvent.getDeviceId(), keyEvent.getSource(), keyEvent.getDisplayId(),
                 policyFlags, action, flags,
-                keyEvent->getKeyCode(), keyEvent->getScanCode(), keyEvent->getMetaState(),
-                keyEvent->getRepeatCount(), keyEvent->getDownTime());
+                keyEvent.getKeyCode(), keyEvent.getScanCode(), keyEvent.getMetaState(),
+                keyEvent.getRepeatCount(), keyEvent.getDownTime());
         lastInjectedEntry = firstInjectedEntry;
         break;
     }
@@ -2717,12 +2738,13 @@
         const nsecs_t* sampleEventTimes = motionEvent->getSampleEventTimes();
         const PointerCoords* samplePointerCoords = motionEvent->getSamplePointerCoords();
         firstInjectedEntry = new MotionEntry(*sampleEventTimes,
-                motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
+                motionEvent->getDeviceId(), motionEvent->getSource(), motionEvent->getDisplayId(),
+                policyFlags,
                 action, actionButton, motionEvent->getFlags(),
                 motionEvent->getMetaState(), motionEvent->getButtonState(),
                 motionEvent->getEdgeFlags(),
                 motionEvent->getXPrecision(), motionEvent->getYPrecision(),
-                motionEvent->getDownTime(), displayId,
+                motionEvent->getDownTime(),
                 uint32_t(pointerCount), pointerProperties, samplePointerCoords,
                 motionEvent->getXOffset(), motionEvent->getYOffset());
         lastInjectedEntry = firstInjectedEntry;
@@ -2730,12 +2752,13 @@
             sampleEventTimes += 1;
             samplePointerCoords += pointerCount;
             MotionEntry* nextInjectedEntry = new MotionEntry(*sampleEventTimes,
-                    motionEvent->getDeviceId(), motionEvent->getSource(), policyFlags,
+                    motionEvent->getDeviceId(), motionEvent->getSource(),
+                    motionEvent->getDisplayId(), policyFlags,
                     action, actionButton, motionEvent->getFlags(),
                     motionEvent->getMetaState(), motionEvent->getButtonState(),
                     motionEvent->getEdgeFlags(),
                     motionEvent->getXPrecision(), motionEvent->getYPrecision(),
-                    motionEvent->getDownTime(), displayId,
+                    motionEvent->getDownTime(),
                     uint32_t(pointerCount), pointerProperties, samplePointerCoords,
                     motionEvent->getXOffset(), motionEvent->getYOffset());
             lastInjectedEntry->next = nextInjectedEntry;
@@ -2758,7 +2781,7 @@
     lastInjectedEntry->injectionState = injectionState;
 
     bool needWake = false;
-    for (EventEntry* entry = firstInjectedEntry; entry != NULL; ) {
+    for (EventEntry* entry = firstInjectedEntry; entry != nullptr; ) {
         EventEntry* nextEntry = entry->next;
         needWake |= enqueueInboundEventLocked(entry);
         entry = nextEntry;
@@ -2895,7 +2918,7 @@
             return windowHandle;
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 bool InputDispatcher::hasWindowHandleLocked(
@@ -2923,7 +2946,7 @@
         bool foundHoveredWindow = false;
         for (size_t i = 0; i < mWindowHandles.size(); i++) {
             const sp<InputWindowHandle>& windowHandle = mWindowHandles.itemAt(i);
-            if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == NULL) {
+            if (!windowHandle->updateInfo() || windowHandle->getInputChannel() == nullptr) {
                 mWindowHandles.removeAt(i--);
                 continue;
             }
@@ -2936,24 +2959,24 @@
         }
 
         if (!foundHoveredWindow) {
-            mLastHoverWindowHandle = NULL;
+            mLastHoverWindowHandle = nullptr;
         }
 
         if (mFocusedWindowHandle != newFocusedWindowHandle) {
-            if (mFocusedWindowHandle != NULL) {
+            if (mFocusedWindowHandle != nullptr) {
 #if DEBUG_FOCUS
                 ALOGD("Focus left window: %s",
                         mFocusedWindowHandle->getName().c_str());
 #endif
                 sp<InputChannel> focusedInputChannel = mFocusedWindowHandle->getInputChannel();
-                if (focusedInputChannel != NULL) {
+                if (focusedInputChannel != nullptr) {
                     CancelationOptions options(CancelationOptions::CANCEL_NON_POINTER_EVENTS,
                             "focus left window");
                     synthesizeCancelationEventsForInputChannelLocked(
                             focusedInputChannel, options);
                 }
             }
-            if (newFocusedWindowHandle != NULL) {
+            if (newFocusedWindowHandle != nullptr) {
 #if DEBUG_FOCUS
                 ALOGD("Focus entered window: %s",
                         newFocusedWindowHandle->getName().c_str());
@@ -2973,7 +2996,7 @@
 #endif
                     sp<InputChannel> touchedInputChannel =
                             touchedWindow.windowHandle->getInputChannel();
-                    if (touchedInputChannel != NULL) {
+                    if (touchedInputChannel != nullptr) {
                         CancelationOptions options(CancelationOptions::CANCEL_POINTER_EVENTS,
                                 "touched window was removed");
                         synthesizeCancelationEventsForInputChannelLocked(
@@ -3013,15 +3036,15 @@
     { // acquire lock
         AutoMutex _l(mLock);
 
-        if (inputApplicationHandle != NULL && inputApplicationHandle->updateInfo()) {
+        if (inputApplicationHandle != nullptr && inputApplicationHandle->updateInfo()) {
             if (mFocusedApplicationHandle != inputApplicationHandle) {
-                if (mFocusedApplicationHandle != NULL) {
+                if (mFocusedApplicationHandle != nullptr) {
                     resetANRTimeoutsLocked();
                     mFocusedApplicationHandle->releaseInfo();
                 }
                 mFocusedApplicationHandle = inputApplicationHandle;
             }
-        } else if (mFocusedApplicationHandle != NULL) {
+        } else if (mFocusedApplicationHandle != nullptr) {
             resetANRTimeoutsLocked();
             mFocusedApplicationHandle->releaseInfo();
             mFocusedApplicationHandle.clear();
@@ -3103,7 +3126,7 @@
 
         sp<InputWindowHandle> fromWindowHandle = getWindowHandleLocked(fromChannel);
         sp<InputWindowHandle> toWindowHandle = getWindowHandleLocked(toChannel);
-        if (fromWindowHandle == NULL || toWindowHandle == NULL) {
+        if (fromWindowHandle == nullptr || toWindowHandle == nullptr) {
 #if DEBUG_FOCUS
             ALOGD("Cannot transfer focus because from or to window not found.");
 #endif
@@ -3208,7 +3231,7 @@
     dump += StringPrintf(INDENT "DispatchEnabled: %d\n", mDispatchEnabled);
     dump += StringPrintf(INDENT "DispatchFrozen: %d\n", mDispatchFrozen);
 
-    if (mFocusedApplicationHandle != NULL) {
+    if (mFocusedApplicationHandle != nullptr) {
         dump += StringPrintf(INDENT "FocusedApplication: name='%s', dispatchingTimeout=%0.3fms\n",
                 mFocusedApplicationHandle->getName().c_str(),
                 mFocusedApplicationHandle->getDispatchingTimeout(
@@ -3217,7 +3240,7 @@
         dump += StringPrintf(INDENT "FocusedApplication: <null>\n");
     }
     dump += StringPrintf(INDENT "FocusedWindow: name='%s'\n",
-            mFocusedWindowHandle != NULL ? mFocusedWindowHandle->getName().c_str() : "<null>");
+            mFocusedWindowHandle != nullptr ? mFocusedWindowHandle->getName().c_str() : "<null>");
 
     if (!mTouchStatesByDisplay.isEmpty()) {
         dump += StringPrintf(INDENT "TouchStatesByDisplay:\n");
@@ -3528,7 +3551,7 @@
             dispatchLatency, waitDuration, reason);
 
     // Capture a record of the InputDispatcher state at the time of the ANR.
-    time_t t = time(NULL);
+    time_t t = time(nullptr);
     struct tm tm;
     localtime_r(&t, &tm);
     char timestr[64];
@@ -3583,8 +3606,8 @@
     mLock.lock();
 
     resumeAfterTargetsNotReadyTimeoutLocked(newTimeout,
-            commandEntry->inputWindowHandle != NULL
-                    ? commandEntry->inputWindowHandle->getInputChannel() : NULL);
+            commandEntry->inputWindowHandle != nullptr
+                    ? commandEntry->inputWindowHandle->getInputChannel() : nullptr);
 }
 
 void InputDispatcher::doInterceptKeyBeforeDispatchingLockedInterruptible(
@@ -3817,6 +3840,7 @@
                 keyEntry->eventTime = event.getEventTime();
                 keyEntry->deviceId = event.getDeviceId();
                 keyEntry->source = event.getSource();
+                keyEntry->displayId = event.getDisplayId();
                 keyEntry->flags = event.getFlags() | AKEY_EVENT_FLAG_FALLBACK;
                 keyEntry->keyCode = fallbackKeyCode;
                 keyEntry->scanCode = event.getScanCode();
@@ -3855,7 +3879,7 @@
 }
 
 void InputDispatcher::initializeKeyEvent(KeyEvent* event, const KeyEntry* entry) {
-    event->initialize(entry->deviceId, entry->source, entry->action, entry->flags,
+    event->initialize(entry->deviceId, entry->source, entry->displayId, entry->action, entry->flags,
             entry->keyCode, entry->scanCode, entry->metaState, entry->repeatCount,
             entry->downTime, entry->eventTime);
 }
@@ -3934,7 +3958,7 @@
 
 InputDispatcher::EventEntry::EventEntry(int32_t type, nsecs_t eventTime, uint32_t policyFlags) :
         refCount(1), type(type), eventTime(eventTime), policyFlags(policyFlags),
-        injectionState(NULL), dispatchInProgress(false) {
+        injectionState(nullptr), dispatchInProgress(false) {
 }
 
 InputDispatcher::EventEntry::~EventEntry() {
@@ -3953,7 +3977,7 @@
 void InputDispatcher::EventEntry::releaseInjectionState() {
     if (injectionState) {
         injectionState->release();
-        injectionState = NULL;
+        injectionState = nullptr;
     }
 }
 
@@ -3991,11 +4015,11 @@
 // --- InputDispatcher::KeyEntry ---
 
 InputDispatcher::KeyEntry::KeyEntry(nsecs_t eventTime,
-        int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action,
+        int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action,
         int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
         int32_t repeatCount, nsecs_t downTime) :
         EventEntry(TYPE_KEY, eventTime, policyFlags),
-        deviceId(deviceId), source(source), action(action), flags(flags),
+        deviceId(deviceId), source(source), displayId(displayId), action(action), flags(flags),
         keyCode(keyCode), scanCode(scanCode), metaState(metaState),
         repeatCount(repeatCount), downTime(downTime),
         syntheticRepeat(false), interceptKeyResult(KeyEntry::INTERCEPT_KEY_RESULT_UNKNOWN),
@@ -4006,10 +4030,10 @@
 }
 
 void InputDispatcher::KeyEntry::appendDescription(std::string& msg) const {
-    msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, action=%s, "
+    msg += StringPrintf("KeyEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32 ", action=%s, "
             "flags=0x%08x, keyCode=%d, scanCode=%d, metaState=0x%08x, "
             "repeatCount=%d), policyFlags=0x%08x",
-            deviceId, source, keyActionToString(action).c_str(), flags, keyCode,
+            deviceId, source, displayId, keyActionToString(action).c_str(), flags, keyCode,
             scanCode, metaState, repeatCount, policyFlags);
 }
 
@@ -4026,18 +4050,19 @@
 // --- InputDispatcher::MotionEntry ---
 
 InputDispatcher::MotionEntry::MotionEntry(nsecs_t eventTime, int32_t deviceId,
-        uint32_t source, uint32_t policyFlags, int32_t action, int32_t actionButton,
+        uint32_t source, int32_t displayId, uint32_t policyFlags, int32_t action,
+        int32_t actionButton,
         int32_t flags, int32_t metaState, int32_t buttonState, int32_t edgeFlags,
         float xPrecision, float yPrecision, nsecs_t downTime,
-        int32_t displayId, uint32_t pointerCount,
+        uint32_t pointerCount,
         const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
         float xOffset, float yOffset) :
         EventEntry(TYPE_MOTION, eventTime, policyFlags),
         eventTime(eventTime),
-        deviceId(deviceId), source(source), action(action), actionButton(actionButton),
-        flags(flags), metaState(metaState), buttonState(buttonState),
+        deviceId(deviceId), source(source), displayId(displayId), action(action),
+        actionButton(actionButton), flags(flags), metaState(metaState), buttonState(buttonState),
         edgeFlags(edgeFlags), xPrecision(xPrecision), yPrecision(yPrecision),
-        downTime(downTime), displayId(displayId), pointerCount(pointerCount) {
+        downTime(downTime), pointerCount(pointerCount) {
     for (uint32_t i = 0; i < pointerCount; i++) {
         this->pointerProperties[i].copyFrom(pointerProperties[i]);
         this->pointerCoords[i].copyFrom(pointerCoords[i]);
@@ -4051,11 +4076,12 @@
 }
 
 void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const {
-    msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, action=%s, actionButton=0x%08x, "
-            "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, "
-            "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[",
-            deviceId, source, motionActionToString(action).c_str(), actionButton, flags, metaState,
-            buttonState, edgeFlags, xPrecision, yPrecision, displayId);
+    msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32
+            ", action=%s, actionButton=0x%08x, flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, "
+            "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, pointers=[",
+            deviceId, source, displayId, motionActionToString(action).c_str(), actionButton, flags,
+            metaState, buttonState, edgeFlags, xPrecision, yPrecision);
+
     for (uint32_t i = 0; i < pointerCount; i++) {
         if (i) {
             msg += ", ";
@@ -4184,8 +4210,8 @@
         }
 #if DEBUG_OUTBOUND_EVENT_DETAILS
         ALOGD("Dropping inconsistent motion up or cancel event: deviceId=%d, source=%08x, "
-                "actionMasked=%d",
-                entry->deviceId, entry->source, actionMasked);
+                "displayId=%" PRId32 ", actionMasked=%d",
+                entry->deviceId, entry->source, entry->displayId, actionMasked);
 #endif
         return false;
     }
@@ -4237,8 +4263,8 @@
         }
 #if DEBUG_OUTBOUND_EVENT_DETAILS
         ALOGD("Dropping inconsistent motion pointer up/down or move event: "
-                "deviceId=%d, source=%08x, actionMasked=%d",
-                entry->deviceId, entry->source, actionMasked);
+                "deviceId=%d, source=%08x, displayId=%" PRId32 ", actionMasked=%d",
+                entry->deviceId, entry->source, entry->displayId, actionMasked);
 #endif
         return false;
     }
@@ -4250,8 +4276,9 @@
             return true;
         }
 #if DEBUG_OUTBOUND_EVENT_DETAILS
-        ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x",
-                entry->deviceId, entry->source);
+        ALOGD("Dropping inconsistent motion hover exit event: deviceId=%d, source=%08x, "
+                "displayId=%" PRId32,
+                entry->deviceId, entry->source, entry->displayId);
 #endif
         return false;
     }
@@ -4276,6 +4303,7 @@
         const KeyMemento& memento = mKeyMementos.itemAt(i);
         if (memento.deviceId == entry->deviceId
                 && memento.source == entry->source
+                && memento.displayId == entry->displayId
                 && memento.keyCode == entry->keyCode
                 && memento.scanCode == entry->scanCode) {
             return i;
@@ -4303,6 +4331,7 @@
     KeyMemento& memento = mKeyMementos.editTop();
     memento.deviceId = entry->deviceId;
     memento.source = entry->source;
+    memento.displayId = entry->displayId;
     memento.keyCode = entry->keyCode;
     memento.scanCode = entry->scanCode;
     memento.metaState = entry->metaState;
@@ -4317,11 +4346,11 @@
     MotionMemento& memento = mMotionMementos.editTop();
     memento.deviceId = entry->deviceId;
     memento.source = entry->source;
+    memento.displayId = entry->displayId;
     memento.flags = flags;
     memento.xPrecision = entry->xPrecision;
     memento.yPrecision = entry->yPrecision;
     memento.downTime = entry->downTime;
-    memento.displayId = entry->displayId;
     memento.setPointers(entry);
     memento.hovering = hovering;
     memento.policyFlags = entry->policyFlags;
@@ -4341,7 +4370,7 @@
         const KeyMemento& memento = mKeyMementos.itemAt(i);
         if (shouldCancelKey(memento, options)) {
             outEvents.push(new KeyEntry(currentTime,
-                    memento.deviceId, memento.source, memento.policyFlags,
+                    memento.deviceId, memento.source, memento.displayId, memento.policyFlags,
                     AKEY_EVENT_ACTION_UP, memento.flags | AKEY_EVENT_FLAG_CANCELED,
                     memento.keyCode, memento.scanCode, memento.metaState, 0, memento.downTime));
         }
@@ -4351,13 +4380,12 @@
         const MotionMemento& memento = mMotionMementos.itemAt(i);
         if (shouldCancelMotion(memento, options)) {
             outEvents.push(new MotionEntry(currentTime,
-                    memento.deviceId, memento.source, memento.policyFlags,
+                    memento.deviceId, memento.source, memento.displayId, memento.policyFlags,
                     memento.hovering
                             ? AMOTION_EVENT_ACTION_HOVER_EXIT
                             : AMOTION_EVENT_ACTION_CANCEL,
                     memento.flags, 0, 0, 0, 0,
                     memento.xPrecision, memento.yPrecision, memento.downTime,
-                    memento.displayId,
                     memento.pointerCount, memento.pointerProperties, memento.pointerCoords,
                     0, 0));
         }
@@ -4461,7 +4489,7 @@
 }
 
 const std::string InputDispatcher::Connection::getWindowName() const {
-    if (inputWindowHandle != NULL) {
+    if (inputWindowHandle != nullptr) {
         return inputWindowHandle->getName();
     }
     if (monitor) {
@@ -4487,19 +4515,19 @@
 }
 
 InputDispatcher::DispatchEntry* InputDispatcher::Connection::findWaitQueueEntry(uint32_t seq) {
-    for (DispatchEntry* entry = waitQueue.head; entry != NULL; entry = entry->next) {
+    for (DispatchEntry* entry = waitQueue.head; entry != nullptr; entry = entry->next) {
         if (entry->seq == seq) {
             return entry;
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 
 // --- InputDispatcher::CommandEntry ---
 
 InputDispatcher::CommandEntry::CommandEntry(Command command) :
-    command(command), eventTime(0), keyEntry(NULL), userActivityEventType(0),
+    command(command), eventTime(0), keyEntry(nullptr), userActivityEventType(0),
     seq(0), handled(false) {
 }
 
@@ -4510,7 +4538,7 @@
 // --- InputDispatcher::TouchState ---
 
 InputDispatcher::TouchState::TouchState() :
-    down(false), split(false), deviceId(-1), source(0), displayId(-1) {
+    down(false), split(false), deviceId(-1), source(0), displayId(ADISPLAY_ID_NONE) {
 }
 
 InputDispatcher::TouchState::~TouchState() {
@@ -4521,7 +4549,7 @@
     split = false;
     deviceId = -1;
     source = 0;
-    displayId = -1;
+    displayId = ADISPLAY_ID_NONE;
     windows.clear();
 }
 
@@ -4590,7 +4618,7 @@
             return window.windowHandle;
         }
     }
-    return NULL;
+    return nullptr;
 }
 
 bool InputDispatcher::TouchState::isSlippery() const {
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 8da8450..31ab339 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -299,7 +299,7 @@
      *
      * This method may be called on any thread (usually by the input manager).
      */
-    virtual int32_t injectInputEvent(const InputEvent* event, int32_t displayId,
+    virtual int32_t injectInputEvent(const InputEvent* event,
             int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
             uint32_t policyFlags) = 0;
 
@@ -383,7 +383,7 @@
     virtual void notifySwitch(const NotifySwitchArgs* args);
     virtual void notifyDeviceReset(const NotifyDeviceResetArgs* args);
 
-    virtual int32_t injectInputEvent(const InputEvent* event, int32_t displayId,
+    virtual int32_t injectInputEvent(const InputEvent* event,
             int32_t injectorPid, int32_t injectorUid, int32_t syncMode, int32_t timeoutMillis,
             uint32_t policyFlags);
 
@@ -406,7 +406,7 @@
         T* prev;
 
     protected:
-        inline Link() : next(NULL), prev(NULL) { }
+        inline Link() : next(nullptr), prev(nullptr) { }
     };
 
     struct InjectionState {
@@ -441,7 +441,7 @@
 
         bool dispatchInProgress; // initially false, set to true while dispatching
 
-        inline bool isInjected() const { return injectionState != NULL; }
+        inline bool isInjected() const { return injectionState != nullptr; }
 
         void release();
 
@@ -474,6 +474,7 @@
     struct KeyEntry : EventEntry {
         int32_t deviceId;
         uint32_t source;
+        int32_t displayId;
         int32_t action;
         int32_t flags;
         int32_t keyCode;
@@ -494,8 +495,8 @@
         nsecs_t interceptKeyWakeupTime; // used with INTERCEPT_KEY_RESULT_TRY_AGAIN_LATER
 
         KeyEntry(nsecs_t eventTime,
-                int32_t deviceId, uint32_t source, uint32_t policyFlags, int32_t action,
-                int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
+                int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags,
+                int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode, int32_t metaState,
                 int32_t repeatCount, nsecs_t downTime);
         virtual void appendDescription(std::string& msg) const;
         void recycle();
@@ -508,6 +509,7 @@
         nsecs_t eventTime;
         int32_t deviceId;
         uint32_t source;
+        int32_t displayId;
         int32_t action;
         int32_t actionButton;
         int32_t flags;
@@ -517,17 +519,15 @@
         float xPrecision;
         float yPrecision;
         nsecs_t downTime;
-        int32_t displayId;
         uint32_t pointerCount;
         PointerProperties pointerProperties[MAX_POINTERS];
         PointerCoords pointerCoords[MAX_POINTERS];
 
         MotionEntry(nsecs_t eventTime,
-                int32_t deviceId, uint32_t source, uint32_t policyFlags,
+                int32_t deviceId, uint32_t source, int32_t displayId, uint32_t policyFlags,
                 int32_t action, int32_t actionButton, int32_t flags,
                 int32_t metaState, int32_t buttonState, int32_t edgeFlags,
-                float xPrecision, float yPrecision, nsecs_t downTime,
-                int32_t displayId, uint32_t pointerCount,
+                float xPrecision, float yPrecision, nsecs_t downTime, uint32_t pointerCount,
                 const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
                 float xOffset, float yOffset);
         virtual void appendDescription(std::string& msg) const;
@@ -614,7 +614,7 @@
         T* tail;
         uint32_t entryCount;
 
-        inline Queue() : head(NULL), tail(NULL), entryCount(0) {
+        inline Queue() : head(nullptr), tail(nullptr), entryCount(0) {
         }
 
         inline bool isEmpty() const {
@@ -629,7 +629,7 @@
             } else {
                 head = entry;
             }
-            entry->next = NULL;
+            entry->next = nullptr;
             tail = entry;
         }
 
@@ -641,7 +641,7 @@
             } else {
                 tail = entry;
             }
-            entry->prev = NULL;
+            entry->prev = nullptr;
             head = entry;
         }
 
@@ -664,9 +664,9 @@
             T* entry = head;
             head = entry->next;
             if (head) {
-                head->prev = NULL;
+                head->prev = nullptr;
             } else {
-                tail = NULL;
+                tail = nullptr;
             }
             return entry;
         }
@@ -754,6 +754,7 @@
         struct KeyMemento {
             int32_t deviceId;
             uint32_t source;
+            int32_t displayId;
             int32_t keyCode;
             int32_t scanCode;
             int32_t metaState;
@@ -765,11 +766,11 @@
         struct MotionMemento {
             int32_t deviceId;
             uint32_t source;
+            int32_t displayId;
             int32_t flags;
             float xPrecision;
             float yPrecision;
             nsecs_t downTime;
-            int32_t displayId;
             uint32_t pointerCount;
             PointerProperties pointerProperties[MAX_POINTERS];
             PointerCoords pointerCoords[MAX_POINTERS];
@@ -932,6 +933,9 @@
     };
     // Maps the key code replaced, device id tuple to the key code it was replaced with
     KeyedVector<KeyReplacement, int32_t> mReplacedKeys;
+    // Process certain Meta + Key combinations
+    void accelerateMetaShortcuts(const int32_t deviceId, const int32_t action,
+            int32_t& keyCode, int32_t& metaState);
 
     // Deferred command processing.
     bool haveCommandsLocked() const;
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 520fea4..25a39a8 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -43,17 +43,18 @@
 // --- NotifyKeyArgs ---
 
 NotifyKeyArgs::NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
-        uint32_t policyFlags,
+        int32_t displayId, uint32_t policyFlags,
         int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
         int32_t metaState, nsecs_t downTime) :
-        eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
+        eventTime(eventTime), deviceId(deviceId), source(source), displayId(displayId),
+        policyFlags(policyFlags),
         action(action), flags(flags), keyCode(keyCode), scanCode(scanCode),
         metaState(metaState), downTime(downTime) {
 }
 
 NotifyKeyArgs::NotifyKeyArgs(const NotifyKeyArgs& other) :
         eventTime(other.eventTime), deviceId(other.deviceId), source(other.source),
-        policyFlags(other.policyFlags),
+        displayId(other.displayId), policyFlags(other.policyFlags),
         action(other.action), flags(other.flags),
         keyCode(other.keyCode), scanCode(other.scanCode),
         metaState(other.metaState), downTime(other.downTime) {
@@ -67,16 +68,17 @@
 // --- NotifyMotionArgs ---
 
 NotifyMotionArgs::NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source,
-        uint32_t policyFlags,
+        int32_t displayId, uint32_t policyFlags,
         int32_t action, int32_t actionButton, int32_t flags, int32_t metaState,
-        int32_t buttonState, int32_t edgeFlags, int32_t displayId, uint32_t deviceTimestamp,
+        int32_t buttonState, int32_t edgeFlags, uint32_t deviceTimestamp,
         uint32_t pointerCount,
         const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
         float xPrecision, float yPrecision, nsecs_t downTime) :
-        eventTime(eventTime), deviceId(deviceId), source(source), policyFlags(policyFlags),
+        eventTime(eventTime), deviceId(deviceId), source(source), displayId(displayId),
+        policyFlags(policyFlags),
         action(action), actionButton(actionButton),
         flags(flags), metaState(metaState), buttonState(buttonState),
-        edgeFlags(edgeFlags), displayId(displayId), deviceTimestamp(deviceTimestamp),
+        edgeFlags(edgeFlags), deviceTimestamp(deviceTimestamp),
         pointerCount(pointerCount),
         xPrecision(xPrecision), yPrecision(yPrecision), downTime(downTime) {
     for (uint32_t i = 0; i < pointerCount; i++) {
@@ -87,10 +89,10 @@
 
 NotifyMotionArgs::NotifyMotionArgs(const NotifyMotionArgs& other) :
         eventTime(other.eventTime), deviceId(other.deviceId), source(other.source),
-        policyFlags(other.policyFlags),
+        displayId(other.displayId), policyFlags(other.policyFlags),
         action(other.action), actionButton(other.actionButton), flags(other.flags),
         metaState(other.metaState), buttonState(other.buttonState),
-        edgeFlags(other.edgeFlags), displayId(other.displayId),
+        edgeFlags(other.edgeFlags),
         deviceTimestamp(other.deviceTimestamp), pointerCount(other.pointerCount),
         xPrecision(other.xPrecision), yPrecision(other.yPrecision), downTime(other.downTime) {
     for (uint32_t i = 0; i < pointerCount; i++) {
diff --git a/services/inputflinger/InputListener.h b/services/inputflinger/InputListener.h
index 77afb34..a3d919b 100644
--- a/services/inputflinger/InputListener.h
+++ b/services/inputflinger/InputListener.h
@@ -55,6 +55,7 @@
     nsecs_t eventTime;
     int32_t deviceId;
     uint32_t source;
+    int32_t displayId;
     uint32_t policyFlags;
     int32_t action;
     int32_t flags;
@@ -65,8 +66,8 @@
 
     inline NotifyKeyArgs() { }
 
-    NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
-            int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
+    NotifyKeyArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
+            uint32_t policyFlags, int32_t action, int32_t flags, int32_t keyCode, int32_t scanCode,
             int32_t metaState, nsecs_t downTime);
 
     NotifyKeyArgs(const NotifyKeyArgs& other);
@@ -82,6 +83,7 @@
     nsecs_t eventTime;
     int32_t deviceId;
     uint32_t source;
+    int32_t displayId;
     uint32_t policyFlags;
     int32_t action;
     int32_t actionButton;
@@ -89,7 +91,6 @@
     int32_t metaState;
     int32_t buttonState;
     int32_t edgeFlags;
-    int32_t displayId;
     /**
      * A timestamp in the input device's time base, not the platform's.
      * The units are microseconds since the last reset.
@@ -106,10 +107,11 @@
 
     inline NotifyMotionArgs() { }
 
-    NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, uint32_t policyFlags,
+    NotifyMotionArgs(nsecs_t eventTime, int32_t deviceId, uint32_t source, int32_t displayId,
+            uint32_t policyFlags,
             int32_t action, int32_t actionButton, int32_t flags,
             int32_t metaState, int32_t buttonState,
-            int32_t edgeFlags, int32_t displayId, uint32_t deviceTimestamp, uint32_t pointerCount,
+            int32_t edgeFlags, uint32_t deviceTimestamp, uint32_t pointerCount,
             const PointerProperties* pointerProperties, const PointerCoords* pointerCoords,
             float xPrecision, float yPrecision, nsecs_t downTime);
 
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index e0cd8a0..5adb75c 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -226,7 +226,7 @@
 }
 
 static void synthesizeButtonKey(InputReaderContext* context, int32_t action,
-        nsecs_t when, int32_t deviceId, uint32_t source,
+        nsecs_t when, int32_t deviceId, uint32_t source, int32_t displayId,
         uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState,
         int32_t buttonState, int32_t keyCode) {
     if (
@@ -236,19 +236,19 @@
             || (action == AKEY_EVENT_ACTION_UP
                     && (lastButtonState & buttonState)
                     && !(currentButtonState & buttonState))) {
-        NotifyKeyArgs args(when, deviceId, source, policyFlags,
+        NotifyKeyArgs args(when, deviceId, source, displayId, policyFlags,
                 action, 0, keyCode, 0, context->getGlobalMetaState(), when);
         context->getListener()->notifyKey(&args);
     }
 }
 
 static void synthesizeButtonKeys(InputReaderContext* context, int32_t action,
-        nsecs_t when, int32_t deviceId, uint32_t source,
+        nsecs_t when, int32_t deviceId, uint32_t source, int32_t displayId,
         uint32_t policyFlags, int32_t lastButtonState, int32_t currentButtonState) {
-    synthesizeButtonKey(context, action, when, deviceId, source, policyFlags,
+    synthesizeButtonKey(context, action, when, deviceId, source, displayId, policyFlags,
             lastButtonState, currentButtonState,
             AMOTION_EVENT_BUTTON_BACK, AKEYCODE_BACK);
-    synthesizeButtonKey(context, action, when, deviceId, source, policyFlags,
+    synthesizeButtonKey(context, action, when, deviceId, source, displayId, policyFlags,
             lastButtonState, currentButtonState,
             AMOTION_EVENT_BUTTON_FORWARD, AKEYCODE_FORWARD);
 }
@@ -258,8 +258,8 @@
 
 bool InputReaderConfiguration::getDisplayViewport(ViewportType viewportType,
         const String8* uniqueDisplayId, DisplayViewport* outViewport) const {
-    const DisplayViewport* viewport = NULL;
-    if (viewportType == ViewportType::VIEWPORT_VIRTUAL && uniqueDisplayId != NULL) {
+    const DisplayViewport* viewport = nullptr;
+    if (viewportType == ViewportType::VIEWPORT_VIRTUAL && uniqueDisplayId != nullptr) {
         for (const DisplayViewport& currentViewport : mVirtualDisplays) {
             if (currentViewport.uniqueId == *uniqueDisplayId) {
                 viewport = &currentViewport;
@@ -272,7 +272,7 @@
         viewport = &mInternalDisplay;
     }
 
-    if (viewport != NULL && viewport->displayId >= 0) {
+    if (viewport != nullptr && viewport->displayId >= 0) {
         *outViewport = *viewport;
         return true;
     }
@@ -488,7 +488,7 @@
 }
 
 void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) {
-    InputDevice* device = NULL;
+    InputDevice* device = nullptr;
     ssize_t deviceIndex = mDevices.indexOfKey(deviceId);
     if (deviceIndex < 0) {
         ALOGW("Ignoring spurious device removed event for deviceId %d.", deviceId);
@@ -1786,7 +1786,7 @@
 // --- MultiTouchMotionAccumulator ---
 
 MultiTouchMotionAccumulator::MultiTouchMotionAccumulator() :
-        mCurrentSlot(-1), mSlots(NULL), mSlotCount(0), mUsingSlotsProtocol(false),
+        mCurrentSlot(-1), mSlots(nullptr), mSlotCount(0), mUsingSlotsProtocol(false),
         mHaveStylus(false), mDeviceTimestamp(0) {
 }
 
@@ -2240,8 +2240,7 @@
 
 KeyboardInputMapper::KeyboardInputMapper(InputDevice* device,
         uint32_t source, int32_t keyboardType) :
-        InputMapper(device), mSource(source),
-        mKeyboardType(keyboardType) {
+        InputMapper(device), mSource(source), mKeyboardType(keyboardType) {
 }
 
 KeyboardInputMapper::~KeyboardInputMapper() {
@@ -2251,6 +2250,20 @@
     return mSource;
 }
 
+int32_t KeyboardInputMapper::getOrientation() {
+    if (mViewport) {
+        return mViewport->orientation;
+    }
+    return DISPLAY_ORIENTATION_0;
+}
+
+int32_t KeyboardInputMapper::getDisplayId() {
+    if (mViewport) {
+        return mViewport->displayId;
+    }
+    return ADISPLAY_ID_NONE;
+}
+
 void KeyboardInputMapper::populateDeviceInfo(InputDeviceInfo* info) {
     InputMapper::populateDeviceInfo(info);
 
@@ -2262,7 +2275,7 @@
     dump += INDENT2 "Keyboard Input Mapper:\n";
     dumpParameters(dump);
     dump += StringPrintf(INDENT3 "KeyboardType: %d\n", mKeyboardType);
-    dump += StringPrintf(INDENT3 "Orientation: %d\n", mOrientation);
+    dump += StringPrintf(INDENT3 "Orientation: %d\n", getOrientation());
     dump += StringPrintf(INDENT3 "KeyDowns: %zu keys currently down\n", mKeyDowns.size());
     dump += StringPrintf(INDENT3 "MetaState: 0x%0x\n", mMetaState);
     dump += StringPrintf(INDENT3 "DownTime: %" PRId64 "\n", mDownTime);
@@ -2279,15 +2292,10 @@
     }
 
     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
-        if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
-            DisplayViewport v;
-            if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, NULL, &v)) {
-                mOrientation = v.orientation;
-            } else {
-                mOrientation = DISPLAY_ORIENTATION_0;
-            }
-        } else {
-            mOrientation = DISPLAY_ORIENTATION_0;
+        if (mParameters.orientationAware) {
+            DisplayViewport dvp;
+            config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, nullptr, &dvp);
+            mViewport = dvp;
         }
     }
 }
@@ -2310,10 +2318,7 @@
     config.tryGetProperty(String8("keyboard.orientationAware"),
             mParameters.orientationAware);
 
-    mParameters.hasAssociatedDisplay = false;
     if (mParameters.orientationAware) {
-        mParameters.hasAssociatedDisplay = true;
-
         mapStemKey(AKEYCODE_STEM_PRIMARY, config, "keyboard.rotated.stem_primary");
         mapStemKey(AKEYCODE_STEM_1, config, "keyboard.rotated.stem_1");
         mapStemKey(AKEYCODE_STEM_2, config, "keyboard.rotated.stem_2");
@@ -2327,8 +2332,6 @@
 
 void KeyboardInputMapper::dumpParameters(std::string& dump) {
     dump += INDENT3 "Parameters:\n";
-    dump += StringPrintf(INDENT4 "HasAssociatedDisplay: %s\n",
-            toString(mParameters.hasAssociatedDisplay));
     dump += StringPrintf(INDENT4 "OrientationAware: %s\n",
             toString(mParameters.orientationAware));
     dump += StringPrintf(INDENT4 "HandlesKeyRepeat: %s\n",
@@ -2423,8 +2426,8 @@
 
     if (down) {
         // Rotate key codes according to orientation if needed.
-        if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
-            keyCode = rotateKeyCode(keyCode, mOrientation);
+        if (mParameters.orientationAware) {
+            keyCode = rotateKeyCode(keyCode, getOrientation());
         }
 
         // Add key down.
@@ -2489,7 +2492,7 @@
         policyFlags |= POLICY_FLAG_DISABLE_KEY_REPEAT;
     }
 
-    NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
+    NotifyKeyArgs args(when, getDeviceId(), mSource, getDisplayId(), policyFlags,
             down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
             AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
     getListener()->notifyKey(&args);
@@ -2699,15 +2702,12 @@
     }
 
     if (!changes || (changes & InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
+        mOrientation = DISPLAY_ORIENTATION_0;
         if (mParameters.orientationAware && mParameters.hasAssociatedDisplay) {
             DisplayViewport v;
-            if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, NULL, &v)) {
+            if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, nullptr, &v)) {
                 mOrientation = v.orientation;
-            } else {
-                mOrientation = DISPLAY_ORIENTATION_0;
             }
-        } else {
-            mOrientation = DISPLAY_ORIENTATION_0;
         }
         bumpGeneration();
     }
@@ -2826,8 +2826,8 @@
     float hscroll = mCursorScrollAccumulator.getRelativeHWheel();
     bool scrolled = vscroll != 0 || hscroll != 0;
 
-    mWheelYVelocityControl.move(when, NULL, &vscroll);
-    mWheelXVelocityControl.move(when, &hscroll, NULL);
+    mWheelYVelocityControl.move(when, nullptr, &vscroll);
+    mWheelXVelocityControl.move(when, &hscroll, nullptr);
 
     mPointerVelocityControl.move(when, &deltaX, &deltaY);
 
@@ -2874,7 +2874,7 @@
 
     // Synthesize key down from buttons if needed.
     synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
-            policyFlags, lastButtonState, currentButtonState);
+            displayId, policyFlags, lastButtonState, currentButtonState);
 
     // Send motion event.
     if (downChanged || moved || scrolled || buttonsChanged) {
@@ -2894,19 +2894,19 @@
             while (!released.isEmpty()) {
                 int32_t actionButton = BitSet32::valueForBit(released.clearFirstMarkedBit());
                 buttonState &= ~actionButton;
-                NotifyMotionArgs releaseArgs(when, getDeviceId(), mSource, policyFlags,
+                NotifyMotionArgs releaseArgs(when, getDeviceId(), mSource, displayId, policyFlags,
                         AMOTION_EVENT_ACTION_BUTTON_RELEASE, actionButton, 0,
                         metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-                        displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+                        /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                         mXPrecision, mYPrecision, downTime);
                 getListener()->notifyMotion(&releaseArgs);
             }
         }
 
-        NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+        NotifyMotionArgs args(when, getDeviceId(), mSource, displayId, policyFlags,
                 motionEventAction, 0, 0, metaState, currentButtonState,
                 AMOTION_EVENT_EDGE_FLAG_NONE,
-                displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+                /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 mXPrecision, mYPrecision, downTime);
         getListener()->notifyMotion(&args);
 
@@ -2915,10 +2915,10 @@
             while (!pressed.isEmpty()) {
                 int32_t actionButton = BitSet32::valueForBit(pressed.clearFirstMarkedBit());
                 buttonState |= actionButton;
-                NotifyMotionArgs pressArgs(when, getDeviceId(), mSource, policyFlags,
+                NotifyMotionArgs pressArgs(when, getDeviceId(), mSource, displayId, policyFlags,
                         AMOTION_EVENT_ACTION_BUTTON_PRESS, actionButton, 0,
                         metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-                        displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+                        /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                         mXPrecision, mYPrecision, downTime);
                 getListener()->notifyMotion(&pressArgs);
             }
@@ -2929,10 +2929,10 @@
         // Send hover move after UP to tell the application that the mouse is hovering now.
         if (motionEventAction == AMOTION_EVENT_ACTION_UP
                 && (mSource == AINPUT_SOURCE_MOUSE)) {
-            NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, policyFlags,
+            NotifyMotionArgs hoverArgs(when, getDeviceId(), mSource, displayId, policyFlags,
                     AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
                     metaState, currentButtonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-                    displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+                    /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                     mXPrecision, mYPrecision, downTime);
             getListener()->notifyMotion(&hoverArgs);
         }
@@ -2942,10 +2942,10 @@
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
             pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
-            NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
+            NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, displayId, policyFlags,
                     AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, currentButtonState,
                     AMOTION_EVENT_EDGE_FLAG_NONE,
-                    displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+                    /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                     mXPrecision, mYPrecision, downTime);
             getListener()->notifyMotion(&scrollArgs);
         }
@@ -2953,7 +2953,7 @@
 
     // Synthesize key up from buttons if needed.
     synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
-            policyFlags, lastButtonState, currentButtonState);
+            displayId, policyFlags, lastButtonState, currentButtonState);
 
     mCursorMotionAccumulator.finishSync();
     mCursorScrollAccumulator.finishSync();
@@ -2968,7 +2968,7 @@
 }
 
 void CursorInputMapper::fadePointer() {
-    if (mPointerController != NULL) {
+    if (mPointerController != nullptr) {
         mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
     }
 }
@@ -3020,7 +3020,7 @@
     }
     if (!changes || (InputReaderConfiguration::CHANGE_DISPLAY_INFO)) {
         DisplayViewport v;
-        if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, NULL, &v)) {
+        if (config->getDisplayViewport(ViewportType::VIEWPORT_INTERNAL, nullptr, &v)) {
             mOrientation = v.orientation;
         } else {
             mOrientation = DISPLAY_ORIENTATION_0;
@@ -3072,10 +3072,10 @@
         int32_t metaState = mContext->getGlobalMetaState();
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_SCROLL, scroll * mScalingFactor);
 
-        NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, policyFlags,
+        NotifyMotionArgs scrollArgs(when, getDeviceId(), mSource, displayId, policyFlags,
                 AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, 0,
                 AMOTION_EVENT_EDGE_FLAG_NONE,
-                displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+                /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 0, 0, 0);
         getListener()->notifyMotion(&scrollArgs);
     }
@@ -3517,7 +3517,7 @@
     // Get associated display dimensions.
     DisplayViewport newViewport;
     if (mParameters.hasAssociatedDisplay) {
-        const String8* uniqueDisplayId = NULL;
+        const String8* uniqueDisplayId = nullptr;
         ViewportType viewportTypeToUse;
 
         if (mParameters.associatedDisplayIsExternal) {
@@ -3621,7 +3621,7 @@
     // Create pointer controller if needed.
     if (mDeviceMode == DEVICE_MODE_POINTER ||
             (mDeviceMode == DEVICE_MODE_DIRECT && mConfig.showTouches)) {
-        if (mPointerController == NULL) {
+        if (mPointerController == nullptr) {
             mPointerController = getPolicy()->obtainPointerController(getDeviceId());
         }
     } else {
@@ -4271,7 +4271,7 @@
     mPointerSimple.reset();
     resetExternalStylus();
 
-    if (mPointerController != NULL) {
+    if (mPointerController != nullptr) {
         mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
         mPointerController->clearSpots();
     }
@@ -4433,7 +4433,8 @@
 
     // Synthesize key down from raw buttons if needed.
     synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource,
-            policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState);
+            mViewport.displayId, policyFlags,
+            mLastCookedState.buttonState, mCurrentCookedState.buttonState);
 
     // Dispatch the touches either directly or by translation through a pointer on screen.
     if (mDeviceMode == DEVICE_MODE_POINTER) {
@@ -4480,7 +4481,7 @@
         dispatchPointerUsage(when, policyFlags, pointerUsage);
     } else {
         if (mDeviceMode == DEVICE_MODE_DIRECT
-                && mConfig.showTouches && mPointerController != NULL) {
+                && mConfig.showTouches && mPointerController != nullptr) {
             mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
             mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
 
@@ -4505,7 +4506,8 @@
 
     // Synthesize key up from raw buttons if needed.
     synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource,
-            policyFlags, mLastCookedState.buttonState, mCurrentCookedState.buttonState);
+            mViewport.displayId, policyFlags,
+            mLastCookedState.buttonState, mCurrentCookedState.buttonState);
 
     // Clear some transient state.
     mCurrentRawState.rawVScroll = 0;
@@ -4720,8 +4722,8 @@
     int32_t metaState = mContext->getGlobalMetaState();
     policyFlags |= POLICY_FLAG_VIRTUAL;
 
-    NotifyKeyArgs args(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, policyFlags,
-            keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
+    NotifyKeyArgs args(when, getDeviceId(), AINPUT_SOURCE_KEYBOARD, mViewport.displayId,
+            policyFlags, keyEventAction, keyEventFlags, keyCode, scanCode, metaState, downTime);
     getListener()->notifyKey(&args);
 }
 
@@ -5413,10 +5415,10 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y);
 
-        NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+        NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0,
                 metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-                mViewport.displayId, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+                /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
                 0, 0, mPointerGesture.downTime);
         getListener()->notifyMotion(&args);
     }
@@ -5458,7 +5460,7 @@
     mPointerVelocityControl.reset();
 
     // Remove any current spots.
-    if (mPointerController != NULL) {
+    if (mPointerController != nullptr) {
         mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
         mPointerController->clearSpots();
     }
@@ -6321,7 +6323,7 @@
         bool down, bool hovering) {
     int32_t metaState = getContext()->getGlobalMetaState();
 
-    if (mPointerController != NULL) {
+    if (mPointerController != nullptr) {
         if (down || hovering) {
             mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
             mPointerController->clearSpots();
@@ -6336,9 +6338,9 @@
         mPointerSimple.down = false;
 
         // Send up.
-        NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+        NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
                  AMOTION_EVENT_ACTION_UP, 0, 0, metaState, mLastRawState.buttonState, 0,
-                 mViewport.displayId, /* deviceTimestamp */ 0,
+                 /* deviceTimestamp */ 0,
                  1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                  mOrientedXPrecision, mOrientedYPrecision,
                  mPointerSimple.downTime);
@@ -6349,9 +6351,9 @@
         mPointerSimple.hovering = false;
 
         // Send hover exit.
-        NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+        NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_EXIT, 0, 0, metaState, mLastRawState.buttonState, 0,
-                mViewport.displayId, /* deviceTimestamp */ 0,
+                /* deviceTimestamp */ 0,
                 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime);
@@ -6364,9 +6366,9 @@
             mPointerSimple.downTime = when;
 
             // Send down.
-            NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+            NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
                     AMOTION_EVENT_ACTION_DOWN, 0, 0, metaState, mCurrentRawState.buttonState, 0,
-                    mViewport.displayId, /* deviceTimestamp */ 0,
+                    /* deviceTimestamp */ 0,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
                     mPointerSimple.downTime);
@@ -6374,9 +6376,9 @@
         }
 
         // Send move.
-        NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+        NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
                 AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, mCurrentRawState.buttonState, 0,
-                mViewport.displayId, /* deviceTimestamp */ 0,
+                /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime);
@@ -6388,10 +6390,10 @@
             mPointerSimple.hovering = true;
 
             // Send hover enter.
-            NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+            NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
                     AMOTION_EVENT_ACTION_HOVER_ENTER, 0, 0, metaState,
                     mCurrentRawState.buttonState, 0,
-                    mViewport.displayId, /* deviceTimestamp */ 0,
+                    /* deviceTimestamp */ 0,
                     1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                     mOrientedXPrecision, mOrientedYPrecision,
                     mPointerSimple.downTime);
@@ -6399,10 +6401,10 @@
         }
 
         // Send hover move.
-        NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+        NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
                 AMOTION_EVENT_ACTION_HOVER_MOVE, 0, 0, metaState,
                 mCurrentRawState.buttonState, 0,
-                mViewport.displayId, /* deviceTimestamp */ 0,
+                /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime);
@@ -6412,8 +6414,8 @@
     if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) {
         float vscroll = mCurrentRawState.rawVScroll;
         float hscroll = mCurrentRawState.rawHScroll;
-        mWheelYVelocityControl.move(when, NULL, &vscroll);
-        mWheelXVelocityControl.move(when, &hscroll, NULL);
+        mWheelYVelocityControl.move(when, nullptr, &vscroll);
+        mWheelXVelocityControl.move(when, &hscroll, nullptr);
 
         // Send scroll.
         PointerCoords pointerCoords;
@@ -6421,9 +6423,9 @@
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_VSCROLL, vscroll);
         pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll);
 
-        NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags,
+        NotifyMotionArgs args(when, getDeviceId(), mSource, mViewport.displayId, policyFlags,
                 AMOTION_EVENT_ACTION_SCROLL, 0, 0, metaState, mCurrentRawState.buttonState, 0,
-                mViewport.displayId, /* deviceTimestamp */ 0,
+                /* deviceTimestamp */ 0,
                 1, &mPointerSimple.currentProperties, &pointerCoords,
                 mOrientedXPrecision, mOrientedYPrecision,
                 mPointerSimple.downTime);
@@ -6484,9 +6486,9 @@
         }
     }
 
-    NotifyMotionArgs args(when, getDeviceId(), source, policyFlags,
+    NotifyMotionArgs args(when, getDeviceId(), source, mViewport.displayId, policyFlags,
             action, actionButton, flags, metaState, buttonState, edgeFlags,
-            mViewport.displayId, deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
+            deviceTimestamp, pointerCount, pointerProperties, pointerCoords,
             xPrecision, yPrecision, downTime);
     getListener()->notifyMotion(&args);
 }
@@ -6520,7 +6522,7 @@
 }
 
 void TouchInputMapper::fadePointer() {
-    if (mPointerController != NULL) {
+    if (mPointerController != nullptr) {
         mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
     }
 }
@@ -6555,7 +6557,7 @@
         }
     }
 
-    return NULL;
+    return nullptr;
 }
 
 void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) {
@@ -7404,9 +7406,10 @@
     // TODO: Use the input device configuration to control this behavior more finely.
     uint32_t policyFlags = 0;
 
-    NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, policyFlags,
+    NotifyMotionArgs args(when, getDeviceId(), AINPUT_SOURCE_JOYSTICK, ADISPLAY_ID_NONE,
+            policyFlags,
             AMOTION_EVENT_ACTION_MOVE, 0, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE,
-            ADISPLAY_ID_NONE, /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
+            /* deviceTimestamp */ 0, 1, &pointerProperties, &pointerCoords,
             0, 0, 0);
     getListener()->notifyMotion(&args);
 }
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index cef3212..89290a8 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -35,6 +35,7 @@
 #include <utils/BitSet.h>
 #include <utils/SortedVector.h>
 
+#include <optional>
 #include <stddef.h>
 #include <unistd.h>
 
@@ -1094,6 +1095,9 @@
     virtual void updateMetaState(int32_t keyCode);
 
 private:
+    // The current viewport.
+    std::optional<DisplayViewport> mViewport;
+
     struct KeyDown {
         int32_t keyCode;
         int32_t scanCode;
@@ -1102,8 +1106,6 @@
     uint32_t mSource;
     int32_t mKeyboardType;
 
-    int32_t mOrientation; // orientation for dpad keys
-
     Vector<KeyDown> mKeyDowns; // keys that are down
     int32_t mMetaState;
     nsecs_t mDownTime; // time of most recent key down
@@ -1120,7 +1122,6 @@
 
     // Immutable configuration parameters.
     struct Parameters {
-        bool hasAssociatedDisplay;
         bool orientationAware;
         bool handlesKeyRepeat;
     } mParameters;
@@ -1128,6 +1129,9 @@
     void configureParameters();
     void dumpParameters(std::string& dump);
 
+    int32_t getOrientation();
+    int32_t getDisplayId();
+
     bool isKeyboardOrGamepadKey(int32_t scanCode);
     bool isMediaKey(int32_t keyCode);
 
diff --git a/services/inputflinger/InputWindow.cpp b/services/inputflinger/InputWindow.cpp
index 3ae7972..0d1dfdd 100644
--- a/services/inputflinger/InputWindow.cpp
+++ b/services/inputflinger/InputWindow.cpp
@@ -66,7 +66,7 @@
 // --- InputWindowHandle ---
 
 InputWindowHandle::InputWindowHandle(const sp<InputApplicationHandle>& inputApplicationHandle) :
-    inputApplicationHandle(inputApplicationHandle), mInfo(NULL) {
+    inputApplicationHandle(inputApplicationHandle), mInfo(nullptr) {
 }
 
 InputWindowHandle::~InputWindowHandle() {
@@ -76,7 +76,7 @@
 void InputWindowHandle::releaseInfo() {
     if (mInfo) {
         delete mInfo;
-        mInfo = NULL;
+        mInfo = nullptr;
     }
 }
 
diff --git a/services/inputflinger/InputWindow.h b/services/inputflinger/InputWindow.h
index 5a48375..c481853 100644
--- a/services/inputflinger/InputWindow.h
+++ b/services/inputflinger/InputWindow.h
@@ -169,7 +169,7 @@
     }
 
     inline sp<InputChannel> getInputChannel() const {
-        return mInfo ? mInfo->inputChannel : NULL;
+        return mInfo ? mInfo->inputChannel : nullptr;
     }
 
     inline std::string getName() const {
diff --git a/services/inputflinger/tests/Android.bp b/services/inputflinger/tests/Android.bp
index dd19800..517e639 100644
--- a/services/inputflinger/tests/Android.bp
+++ b/services/inputflinger/tests/Android.bp
@@ -2,11 +2,11 @@
 
 cc_test {
     name: "inputflinger_tests",
+    cpp_std: "c++17",
     srcs: [
         "InputReader_test.cpp",
         "InputDispatcher_test.cpp",
     ],
-    test_per_src: true,
     cflags: [
         "-Wall",
         "-Werror",
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index aa6df24..0e26d4a 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -28,7 +28,7 @@
 static const int32_t DEVICE_ID = 1;
 
 // An arbitrary display id.
-static const int32_t DISPLAY_ID = 0;
+static const int32_t DISPLAY_ID = ADISPLAY_ID_DEFAULT;
 
 // An arbitrary injector pid / uid pair that has permission to inject events.
 static const int32_t INJECTOR_PID = 999;
@@ -120,20 +120,20 @@
     KeyEvent event;
 
     // Rejects undefined key actions.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
             /*action*/ -1, 0,
             AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
-            &event, DISPLAY_ID,
+            &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject key events with undefined action.";
 
     // Rejects ACTION_MULTIPLE since it is not supported despite being defined in the API.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD,
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_KEYBOARD, ADISPLAY_ID_NONE,
             AKEY_EVENT_ACTION_MULTIPLE, 0,
             AKEYCODE_A, KEY_A, AMETA_NONE, 0, ARBITRARY_TIME, ARBITRARY_TIME);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
-            &event, DISPLAY_ID,
+            &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject key events with ACTION_MULTIPLE.";
 }
@@ -149,106 +149,106 @@
     }
 
     // Rejects undefined motion actions.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
             /*action*/ -1, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
-            &event, DISPLAY_ID,
+            &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with undefined action.";
 
     // Rejects pointer down with invalid index.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_DOWN | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
             0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
-            &event, DISPLAY_ID,
+            &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer down index too large.";
 
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_DOWN | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
             0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
-            &event, DISPLAY_ID,
+            &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer down index too small.";
 
     // Rejects pointer up with invalid index.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_UP | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
             0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
-            &event, DISPLAY_ID,
+            &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer up index too large.";
 
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
             AMOTION_EVENT_ACTION_POINTER_UP | (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
             0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
-            &event, DISPLAY_ID,
+            &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer up index too small.";
 
     // Rejects motion events with invalid number of pointers.
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
             AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 0, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
-            &event, DISPLAY_ID,
+            &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with 0 pointers.";
 
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
             AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
-            &event, DISPLAY_ID,
+            &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with more than MAX_POINTERS pointers.";
 
     // Rejects motion events with invalid pointer ids.
     pointerProperties[0].id = -1;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
             AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
-            &event, DISPLAY_ID,
+            &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer ids less than 0.";
 
     pointerProperties[0].id = MAX_POINTER_ID + 1;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
             AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
-            &event, DISPLAY_ID,
+            &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with pointer ids greater than MAX_POINTER_ID.";
 
     // Rejects motion events with duplicate pointer ids.
     pointerProperties[0].id = 1;
     pointerProperties[1].id = 1;
-    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN,
+    event.initialize(DEVICE_ID, AINPUT_SOURCE_TOUCHSCREEN, DISPLAY_ID,
             AMOTION_EVENT_ACTION_DOWN, 0, 0, 0, AMETA_NONE, 0, 0, 0, 0, 0,
             ARBITRARY_TIME, ARBITRARY_TIME,
             /*pointerCount*/ 2, pointerProperties, pointerCoords);
     ASSERT_EQ(INPUT_EVENT_INJECTION_FAILED, mDispatcher->injectInputEvent(
-            &event, DISPLAY_ID,
+            &event,
             INJECTOR_PID, INJECTOR_UID, INPUT_EVENT_INJECTION_SYNC_NONE, 0, 0))
             << "Should reject motion events with duplicate pointer ids.";
 }
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 22f15a0..286cf88 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -236,7 +236,7 @@
     }
 
     virtual sp<KeyCharacterMap> getKeyboardLayoutOverlay(const InputDeviceIdentifier&) {
-        return NULL;
+        return nullptr;
     }
 
     virtual String8 getDeviceAlias(const InputDeviceIdentifier&) {
@@ -263,7 +263,7 @@
     }
 
     void assertNotifyConfigurationChangedWasCalled(
-            NotifyConfigurationChangedArgs* outEventArgs = NULL) {
+            NotifyConfigurationChangedArgs* outEventArgs = nullptr) {
         ASSERT_FALSE(mNotifyConfigurationChangedArgsQueue.empty())
                 << "Expected notifyConfigurationChanged() to have been called.";
         if (outEventArgs) {
@@ -278,7 +278,7 @@
     }
 
     void assertNotifyDeviceResetWasCalled(
-            NotifyDeviceResetArgs* outEventArgs = NULL) {
+            NotifyDeviceResetArgs* outEventArgs = nullptr) {
         ASSERT_FALSE(mNotifyDeviceResetArgsQueue.empty())
                 << "Expected notifyDeviceReset() to have been called.";
         if (outEventArgs) {
@@ -292,7 +292,7 @@
                 << "Expected notifyDeviceReset() to not have been called.";
     }
 
-    void assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs = NULL) {
+    void assertNotifyKeyWasCalled(NotifyKeyArgs* outEventArgs = nullptr) {
         ASSERT_FALSE(mNotifyKeyArgsQueue.empty())
                 << "Expected notifyKey() to have been called.";
         if (outEventArgs) {
@@ -306,7 +306,7 @@
                 << "Expected notifyKey() to not have been called.";
     }
 
-    void assertNotifyMotionWasCalled(NotifyMotionArgs* outEventArgs = NULL) {
+    void assertNotifyMotionWasCalled(NotifyMotionArgs* outEventArgs = nullptr) {
         ASSERT_FALSE(mNotifyMotionArgsQueue.empty())
                 << "Expected notifyMotion() to have been called.";
         if (outEventArgs) {
@@ -320,7 +320,7 @@
                 << "Expected notifyMotion() to not have been called.";
     }
 
-    void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = NULL) {
+    void assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs = nullptr) {
         ASSERT_FALSE(mNotifySwitchArgsQueue.empty())
                 << "Expected notifySwitch() to have been called.";
         if (outEventArgs) {
@@ -422,7 +422,7 @@
 
     bool isDeviceEnabled(int32_t deviceId) {
         Device* device = getDevice(deviceId);
-        if (device == NULL) {
+        if (device == nullptr) {
             ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
             return false;
         }
@@ -432,7 +432,7 @@
     status_t enableDevice(int32_t deviceId) {
         status_t result;
         Device* device = getDevice(deviceId);
-        if (device == NULL) {
+        if (device == nullptr) {
             ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
             return BAD_VALUE;
         }
@@ -446,7 +446,7 @@
 
     status_t disableDevice(int32_t deviceId) {
         Device* device = getDevice(deviceId);
-        if (device == NULL) {
+        if (device == nullptr) {
             ALOGE("Incorrect device id=%" PRId32 " provided to %s", deviceId, __func__);
             return BAD_VALUE;
         }
@@ -651,7 +651,7 @@
                 return &device->keysByScanCode.valueAt(index);
             }
         }
-        return NULL;
+        return nullptr;
     }
 
     virtual status_t mapAxis(int32_t, int32_t, AxisInfo*) const {
@@ -781,7 +781,7 @@
     }
 
     virtual sp<KeyCharacterMap> getKeyCharacterMap(int32_t) const {
-        return NULL;
+        return nullptr;
     }
 
     virtual bool setKeyboardLayoutOverlay(int32_t, const sp<KeyCharacterMap>&) {
@@ -940,7 +940,7 @@
         mResetWasCalled = false;
     }
 
-    void assertProcessWasCalled(RawEvent* outLastEvent = NULL) {
+    void assertProcessWasCalled(RawEvent* outLastEvent = nullptr) {
         ASSERT_TRUE(mProcessWasCalled)
                 << "Expected process() to have been called.";
         if (outLastEvent) {
@@ -1039,7 +1039,7 @@
             const sp<InputReaderPolicyInterface>& policy,
             const sp<InputListenerInterface>& listener) :
             InputReader(eventHub, policy, listener),
-            mNextDevice(NULL) {
+            mNextDevice(nullptr) {
     }
 
     virtual ~InstrumentedInputReader() {
@@ -1066,7 +1066,7 @@
             const InputDeviceIdentifier& identifier, uint32_t classes) {
         if (mNextDevice) {
             InputDevice* device = mNextDevice;
-            mNextDevice = NULL;
+            mNextDevice = nullptr;
             return device;
         }
         return InputReader::createDeviceLocked(deviceId, controllerNumber, identifier, classes);
@@ -1142,9 +1142,9 @@
 
 TEST_F(InputReaderTest, GetInputDevices) {
     ASSERT_NO_FATAL_FAILURE(addDevice(1, String8("keyboard"),
-            INPUT_DEVICE_CLASS_KEYBOARD, NULL));
+            INPUT_DEVICE_CLASS_KEYBOARD, nullptr));
     ASSERT_NO_FATAL_FAILURE(addDevice(2, String8("ignored"),
-            0, NULL)); // no classes so device will be ignored
+            0, nullptr)); // no classes so device will be ignored
 
     Vector<InputDeviceInfo> inputDevices;
     mReader->getInputDevices(inputDevices);
@@ -1174,9 +1174,9 @@
     FakeInputMapper* mapper = new FakeInputMapper(device, AINPUT_SOURCE_KEYBOARD);
     device->addMapper(mapper);
     mReader->setNextDevice(device);
-    addDevice(deviceId, String8("fake"), deviceClass, NULL);
+    addDevice(deviceId, String8("fake"), deviceClass, nullptr);
 
-    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(NULL));
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyConfigurationChangedWasCalled(nullptr));
 
     NotifyDeviceResetArgs resetArgs;
     ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyDeviceResetWasCalled(&resetArgs));
@@ -1207,9 +1207,9 @@
 }
 
 TEST_F(InputReaderTest, GetKeyCodeState_ForwardsRequestsToMappers) {
-    FakeInputMapper* mapper = NULL;
+    FakeInputMapper* mapper = nullptr;
     ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
-            INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
+            INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
     mapper->setKeyCodeState(AKEYCODE_A, AKEY_STATE_DOWN);
 
     ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getKeyCodeState(0,
@@ -1234,9 +1234,9 @@
 }
 
 TEST_F(InputReaderTest, GetScanCodeState_ForwardsRequestsToMappers) {
-    FakeInputMapper* mapper = NULL;
+    FakeInputMapper* mapper = nullptr;
     ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
-            INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
+            INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
     mapper->setScanCodeState(KEY_A, AKEY_STATE_DOWN);
 
     ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getScanCodeState(0,
@@ -1261,9 +1261,9 @@
 }
 
 TEST_F(InputReaderTest, GetSwitchState_ForwardsRequestsToMappers) {
-    FakeInputMapper* mapper = NULL;
+    FakeInputMapper* mapper = nullptr;
     ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
-            INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
+            INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
     mapper->setSwitchState(SW_LID, AKEY_STATE_DOWN);
 
     ASSERT_EQ(AKEY_STATE_UNKNOWN, mReader->getSwitchState(0,
@@ -1288,9 +1288,9 @@
 }
 
 TEST_F(InputReaderTest, MarkSupportedKeyCodes_ForwardsRequestsToMappers) {
-    FakeInputMapper* mapper = NULL;
+    FakeInputMapper* mapper = nullptr;
     ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
-            INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
+            INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
     mapper->addSupportedKeyCode(AKEYCODE_A);
     mapper->addSupportedKeyCode(AKEYCODE_B);
 
@@ -1323,7 +1323,7 @@
 }
 
 TEST_F(InputReaderTest, LoopOnce_WhenDeviceScanFinished_SendsConfigurationChanged) {
-    addDevice(1, String8("ignored"), INPUT_DEVICE_CLASS_KEYBOARD, NULL);
+    addDevice(1, String8("ignored"), INPUT_DEVICE_CLASS_KEYBOARD, nullptr);
 
     NotifyConfigurationChangedArgs args;
 
@@ -1332,9 +1332,9 @@
 }
 
 TEST_F(InputReaderTest, LoopOnce_ForwardsRawEventsToMappers) {
-    FakeInputMapper* mapper = NULL;
+    FakeInputMapper* mapper = nullptr;
     ASSERT_NO_FATAL_FAILURE(mapper = addDeviceWithFakeInputMapper(1, 0, String8("fake"),
-            INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, NULL));
+            INPUT_DEVICE_CLASS_KEYBOARD, AINPUT_SOURCE_KEYBOARD, nullptr));
 
     mFakeEventHub->enqueueEvent(0, 1, EV_KEY, KEY_A, 1);
     mReader->loopOnce();
@@ -1621,7 +1621,7 @@
     static void assertMotionRange(const InputDeviceInfo& info,
             int32_t axis, uint32_t source, float min, float max, float flat, float fuzz) {
         const InputDeviceInfo::MotionRange* range = info.getMotionRange(axis, source);
-        ASSERT_TRUE(range != NULL) << "Axis: " << axis << " Source: " << source;
+        ASSERT_TRUE(range != nullptr) << "Axis: " << axis << " Source: " << source;
         ASSERT_EQ(axis, range->axis) << "Axis: " << axis << " Source: " << source;
         ASSERT_EQ(source, range->source) << "Axis: " << axis << " Source: " << source;
         ASSERT_NEAR(min, range->min, EPSILON) << "Axis: " << axis << " Source: " << source;
@@ -1996,6 +1996,64 @@
     ASSERT_EQ(AKEYCODE_DPAD_RIGHT, args.keyCode);
 }
 
+TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_NotOrientationAware) {
+    // If the keyboard is not orientation aware,
+    // key events should not be associated with a specific display id
+    mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+
+    KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
+            AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+    addMapperAndConfigure(mapper);
+    NotifyKeyArgs args;
+
+    // Display id should be ADISPLAY_ID_NONE without any display configuration.
+    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(ADISPLAY_ID_NONE, args.displayId);
+
+    setDisplayInfoAndReconfigure(DISPLAY_ID,
+            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
+    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(ADISPLAY_ID_NONE, args.displayId);
+}
+
+TEST_F(KeyboardInputMapperTest, DisplayIdConfigurationChange_OrientationAware) {
+    // If the keyboard is orientation aware,
+    // key events should be associated with the internal viewport
+    mFakeEventHub->addKey(DEVICE_ID, KEY_UP, 0, AKEYCODE_DPAD_UP, 0);
+
+    KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
+            AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
+    addConfigurationProperty("keyboard.orientationAware", "1");
+    addMapperAndConfigure(mapper);
+    NotifyKeyArgs args;
+
+    // Display id should be ADISPLAY_ID_NONE without any display configuration.
+    // ^--- already checked by the previous test
+
+    setDisplayInfoAndReconfigure(DISPLAY_ID,
+            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
+    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(DISPLAY_ID, args.displayId);
+
+    constexpr int32_t newDisplayId = 2;
+    setDisplayInfoAndReconfigure(newDisplayId,
+            DISPLAY_WIDTH, DISPLAY_HEIGHT, DISPLAY_ORIENTATION_0);
+    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 1);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    process(mapper, ARBITRARY_TIME, DEVICE_ID, EV_KEY, KEY_UP, 0);
+    ASSERT_NO_FATAL_FAILURE(mFakeListener->assertNotifyKeyWasCalled(&args));
+    ASSERT_EQ(newDisplayId, args.displayId);
+}
+
 TEST_F(KeyboardInputMapperTest, GetKeyCodeState) {
     KeyboardInputMapper* mapper = new KeyboardInputMapper(mDevice,
             AINPUT_SOURCE_KEYBOARD, AINPUT_KEYBOARD_TYPE_ALPHABETIC);
@@ -2174,8 +2232,8 @@
     mapper->populateDeviceInfo(&info);
 
     // Initially there may not be a valid motion range.
-    ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE));
-    ASSERT_EQ(NULL, info.getMotionRange(AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE));
+    ASSERT_EQ(nullptr, info.getMotionRange(AINPUT_MOTION_RANGE_X, AINPUT_SOURCE_MOUSE));
+    ASSERT_EQ(nullptr, info.getMotionRange(AINPUT_MOTION_RANGE_Y, AINPUT_SOURCE_MOUSE));
     ASSERT_NO_FATAL_FAILURE(assertMotionRange(info,
             AINPUT_MOTION_RANGE_PRESSURE, AINPUT_SOURCE_MOUSE, 0.0f, 1.0f, 0.0f, 0.0f));
 
diff --git a/services/sensorservice/BatteryService.cpp b/services/sensorservice/BatteryService.cpp
index d8e5b29..14f9a12 100644
--- a/services/sensorservice/BatteryService.cpp
+++ b/services/sensorservice/BatteryService.cpp
@@ -94,7 +94,7 @@
 bool BatteryService::checkService() {
     if (mBatteryStatService == nullptr) {
         const sp<IServiceManager> sm(defaultServiceManager());
-        if (sm != NULL) {
+        if (sm != nullptr) {
             const String16 name("batterystats");
             mBatteryStatService = interface_cast<IBatteryStats>(sm->getService(name));
         }
diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp
index 7b00f4d..f2ea02e 100644
--- a/services/sensorservice/RotationVectorSensor.cpp
+++ b/services/sensorservice/RotationVectorSensor.cpp
@@ -94,7 +94,7 @@
             return "GeoMag Rotation Vector Sensor";
         default:
             assert(0);
-            return NULL;
+            return nullptr;
     }
 }
 
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 115a983..ae3f42f 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -208,7 +208,7 @@
 
     if(numHidlTransportErrors > 0) {
         ALOGE("Saw %d Hidl transport failures", numHidlTransportErrors);
-        HidlTransportErrorLog errLog(time(NULL), numHidlTransportErrors);
+        HidlTransportErrorLog errLog(time(nullptr), numHidlTransportErrors);
         mHidlTransportErrors.add(errLog);
         mTotalHidlTransportErrors++;
     }
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index 956844f..0fb4ac6 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -31,7 +31,7 @@
         const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode,
         const String16& opPackageName, bool hasSensorAccess)
     : mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false),
-      mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(NULL),
+      mDead(false), mDataInjectionMode(isDataInjectionMode), mEventCache(nullptr),
       mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), mOpPackageName(opPackageName),
       mDestroyed(false), mHasSensorAccess(hasSensorAccess) {
     mChannel = new BitTube(mService->mSocketBufferSize);
@@ -55,8 +55,8 @@
     }
 
     mService->cleanupConnection(this);
-    if (mEventCache != NULL) {
-        delete mEventCache;
+    if (mEventCache != nullptr) {
+        delete[] mEventCache;
     }
     mDestroyed = true;
 }
@@ -200,7 +200,7 @@
 
     // Add the file descriptor to the Looper for receiving acknowledegments if the app has
     // registered for wake-up sensors OR for sending events in the cache.
-    int ret = looper->addFd(mChannel->getSendFd(), 0, looper_flags, this, NULL);
+    int ret = looper->addFd(mChannel->getSendFd(), 0, looper_flags, this, nullptr);
     if (ret == 1) {
         ALOGD_IF(DEBUG_CONNECTIONS, "%p addFd fd=%d", this, mChannel->getSendFd());
         mHasLooperCallbacks = true;
@@ -224,7 +224,7 @@
         wp<const SensorEventConnection> const * mapFlushEventsToConnections) {
     // filter out events not for this connection
 
-    sensors_event_t* sanitizedBuffer = nullptr;
+    std::unique_ptr<sensors_event_t[]> sanitizedBuffer;
 
     int count = 0;
     Mutex::Autolock _l(mConnectionLock);
@@ -293,7 +293,8 @@
             scratch = const_cast<sensors_event_t *>(buffer);
             count = numEvents;
         } else {
-            scratch = sanitizedBuffer = new sensors_event_t[numEvents];
+            sanitizedBuffer.reset(new sensors_event_t[numEvents]);
+            scratch = sanitizedBuffer.get();
             for (size_t i = 0; i < numEvents; i++) {
                 if (buffer[i].type == SENSOR_TYPE_META_DATA) {
                     scratch[count++] = buffer[i++];
@@ -305,7 +306,6 @@
     sendPendingFlushEventsLocked();
     // Early return if there are no events for this connection.
     if (count == 0) {
-        delete sanitizedBuffer;
         return status_t(NO_ERROR);
     }
 
@@ -323,7 +323,6 @@
             // the max cache size that is desired.
             if (mCacheSize + count < computeMaxCacheSizeLocked()) {
                 reAllocateCacheLocked(scratch, count);
-                delete sanitizedBuffer;
                 return status_t(NO_ERROR);
             }
             // Some events need to be dropped.
@@ -342,7 +341,6 @@
             memcpy(&mEventCache[mCacheSize - numEventsDropped], scratch + remaningCacheSize,
                                             numEventsDropped * sizeof(sensors_event_t));
         }
-        delete sanitizedBuffer;
         return status_t(NO_ERROR);
     }
 
@@ -373,7 +371,7 @@
             --mTotalAcksNeeded;
 #endif
         }
-        if (mEventCache == NULL) {
+        if (mEventCache == nullptr) {
             mMaxCacheSize = computeMaxCacheSizeLocked();
             mEventCache = new sensors_event_t[mMaxCacheSize];
             mCacheSize = 0;
@@ -384,7 +382,6 @@
         // Add this file descriptor to the looper to get a callback when this fd is available for
         // writing.
         updateLooperRegistrationLocked(mService->getLooper());
-        delete sanitizedBuffer;
         return size;
     }
 
@@ -394,7 +391,6 @@
     }
 #endif
 
-    delete sanitizedBuffer;
     return size < 0 ? status_t(size) : status_t(NO_ERROR);
 }
 
@@ -415,7 +411,7 @@
     ALOGD_IF(DEBUG_CONNECTIONS, "reAllocateCacheLocked maxCacheSize=%d %d", mMaxCacheSize,
             new_cache_size);
 
-    delete mEventCache;
+    delete[] mEventCache;
     mEventCache = eventCache_new;
     mCacheSize += count;
     mMaxCacheSize = new_cache_size;
diff --git a/services/sensorservice/SensorEventConnection.h b/services/sensorservice/SensorEventConnection.h
index 032721e..40c21ff 100644
--- a/services/sensorservice/SensorEventConnection.h
+++ b/services/sensorservice/SensorEventConnection.h
@@ -53,7 +53,7 @@
                           bool hasSensorAccess);
 
     status_t sendEvents(sensors_event_t const* buffer, size_t count, sensors_event_t* scratch,
-                        wp<const SensorEventConnection> const * mapFlushEventsToConnections = NULL);
+                        wp<const SensorEventConnection> const * mapFlushEventsToConnections = nullptr);
     bool hasSensor(int32_t handle) const;
     bool hasAnySensor() const;
     bool hasOneShotSensors() const;
diff --git a/services/sensorservice/SensorRecord.cpp b/services/sensorservice/SensorRecord.cpp
index 53fb9de..7c4c6a2 100644
--- a/services/sensorservice/SensorRecord.cpp
+++ b/services/sensorservice/SensorRecord.cpp
@@ -71,7 +71,7 @@
     if (mPendingFlushConnections.size() > 0) {
         return mPendingFlushConnections[0];
     }
-    return NULL;
+    return nullptr;
 }
 
 void SensorService::SensorRecord::clearAllPendingFlushConnections() {
diff --git a/services/sensorservice/SensorRegistrationInfo.h b/services/sensorservice/SensorRegistrationInfo.h
index bba8372..5411515 100644
--- a/services/sensorservice/SensorRegistrationInfo.h
+++ b/services/sensorservice/SensorRegistrationInfo.h
@@ -47,7 +47,7 @@
         mPid = (thread != nullptr) ? thread->getCallingPid() : -1;
         mUid = (thread != nullptr) ? thread->getCallingUid() : -1;
 
-        time_t rawtime = time(NULL);
+        time_t rawtime = time(nullptr);
         struct tm * timeinfo = localtime(&rawtime);
         mHour = static_cast<int8_t>(timeinfo->tm_hour);
         mMin = static_cast<int8_t>(timeinfo->tm_min);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 8e9e7fd..372b609 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -250,7 +250,7 @@
             // it to maxSystemSocketBufferSize if necessary.
             FILE *fp = fopen("/proc/sys/net/core/wmem_max", "r");
             char line[128];
-            if (fp != NULL && fgets(line, sizeof(line), fp) != NULL) {
+            if (fp != nullptr && fgets(line, sizeof(line), fp) != nullptr) {
                 line[sizeof(line) - 1] = '\0';
                 size_t maxSystemSocketBufferSize;
                 sscanf(line, "%zu", &maxSystemSocketBufferSize);
@@ -295,7 +295,7 @@
     {
         Mutex::Autolock _l(mLock);
         for (size_t i = 0 ; i < activeConnections.size(); i++) {
-            if (activeConnections[i] != 0 && activeConnections[i]->getUid() == uid) {
+            if (activeConnections[i] != nullptr && activeConnections[i]->getUid() == uid) {
                 activeConnections[i]->setSensorAccess(hasAccess);
             }
         }
@@ -475,7 +475,7 @@
             result.appendFormat("%zd active connections\n", mActiveConnections.size());
             for (size_t i=0 ; i < mActiveConnections.size() ; i++) {
                 sp<SensorEventConnection> connection(mActiveConnections[i].promote());
-                if (connection != 0) {
+                if (connection != nullptr) {
                     result.appendFormat("Connection Number: %zu \n", i);
                     connection->dump(result);
                 }
@@ -722,11 +722,11 @@
             // on the hardware sensor. mapFlushEventsToConnections[i] will be the
             // SensorEventConnection mapped to the corresponding flush_complete_event in
             // mSensorEventBuffer[i] if such a mapping exists (NULL otherwise).
-            mMapFlushEventsToConnections[i] = NULL;
+            mMapFlushEventsToConnections[i] = nullptr;
             if (mSensorEventBuffer[i].type == SENSOR_TYPE_META_DATA) {
                 const int sensor_handle = mSensorEventBuffer[i].meta_data.sensor;
                 SensorRecord* rec = mActiveSensors.valueFor(sensor_handle);
-                if (rec != NULL) {
+                if (rec != nullptr) {
                     mMapFlushEventsToConnections[i] = rec->getFirstPendingFlushConnection();
                     rec->removeFirstPendingFlushConnection();
                 }
@@ -770,7 +770,7 @@
 
                     size_t numConnections = activeConnections.size();
                     for (size_t i=0 ; i < numConnections; ++i) {
-                        if (activeConnections[i] != NULL) {
+                        if (activeConnections[i] != nullptr) {
                             activeConnections[i]->removeSensor(handle);
                         }
                     }
@@ -783,7 +783,7 @@
         bool needsWakeLock = false;
         size_t numConnections = activeConnections.size();
         for (size_t i=0 ; i < numConnections; ++i) {
-            if (activeConnections[i] != 0) {
+            if (activeConnections[i] != nullptr) {
                 activeConnections[i]->sendEvents(mSensorEventBuffer, count, mSensorEventScratch,
                         mMapFlushEventsToConnections);
                 needsWakeLock |= activeConnections[i]->needsWakeLock();
@@ -816,7 +816,7 @@
     {
         Mutex::Autolock _l(mLock);
         for (size_t i=0 ; i < activeConnections.size(); ++i) {
-            if (activeConnections[i] != 0) {
+            if (activeConnections[i] != nullptr) {
                 activeConnections[i]->resetWakeLockRefCount();
             }
         }
@@ -1021,15 +1021,15 @@
         int requestedMode, const String16& opPackageName) {
     // Only 2 modes supported for a SensorEventConnection ... NORMAL and DATA_INJECTION.
     if (requestedMode != NORMAL && requestedMode != DATA_INJECTION) {
-        return NULL;
+        return nullptr;
     }
 
     Mutex::Autolock _l(mLock);
     // To create a client in DATA_INJECTION mode to inject data, SensorService should already be
     // operating in DI mode.
     if (requestedMode == DATA_INJECTION) {
-        if (mCurrentOperatingMode != DATA_INJECTION) return NULL;
-        if (!isWhiteListedPackage(packageName)) return NULL;
+        if (mCurrentOperatingMode != DATA_INJECTION) return nullptr;
+        if (!isWhiteListedPackage(packageName)) return nullptr;
     }
 
     uid_t uid = IPCThreadState::self()->getCallingUid();
@@ -1325,7 +1325,7 @@
     }
 
     SensorRecord* rec = mActiveSensors.valueFor(handle);
-    if (rec == 0) {
+    if (rec == nullptr) {
         rec = new SensorRecord(connection);
         mActiveSensors.add(handle, rec);
         if (sensor->isVirtual()) {
@@ -1352,7 +1352,7 @@
                             if (isWakeUpSensorEvent(event) && !mWakeLockAcquired) {
                                 setWakeLockAcquiredLocked(true);
                             }
-                            connection->sendEvents(&event, 1, NULL);
+                            connection->sendEvents(&event, 1, nullptr);
                             if (!connection->needsWakeLock() && mWakeLockAcquired) {
                                 checkWakeLockStateLocked();
                             }
@@ -1534,7 +1534,7 @@
             status_t err_flush = sensor->flush(connection.get(), handle);
             if (err_flush == NO_ERROR) {
                 SensorRecord* rec = mActiveSensors.valueFor(handle);
-                if (rec != NULL) rec->addPendingFlushConnection(connection);
+                if (rec != nullptr) rec->addPendingFlushConnection(connection);
             }
             err = (err_flush != NO_ERROR) ? err_flush : err;
         }
@@ -1592,7 +1592,7 @@
     bool releaseLock = true;
     for (size_t i=0 ; i<mActiveConnections.size() ; i++) {
         sp<SensorEventConnection> connection(mActiveConnections[i].promote());
-        if (connection != 0) {
+        if (connection != nullptr) {
             if (connection->needsWakeLock()) {
                 releaseLock = false;
                 break;
@@ -1617,7 +1617,7 @@
     Mutex::Autolock _l(mLock);
     for (size_t i=0 ; i < mActiveConnections.size(); ++i) {
         sp<SensorEventConnection> connection(mActiveConnections[i].promote());
-        if (connection != 0) {
+        if (connection != nullptr) {
             activeConnections->add(connection);
         }
     }
diff --git a/services/sensorservice/hidl/EventQueue.cpp b/services/sensorservice/hidl/EventQueue.cpp
index ff20066..b781744 100644
--- a/services/sensorservice/hidl/EventQueue.cpp
+++ b/services/sensorservice/hidl/EventQueue.cpp
@@ -64,7 +64,7 @@
               mInternalQueue(internalQueue) {
 
     mLooper->addFd(internalQueue->getFd(), ALOOPER_POLL_CALLBACK, ALOOPER_EVENT_INPUT,
-            new EventQueueLooperCallback(internalQueue, callback), NULL /* data */);
+            new EventQueueLooperCallback(internalQueue, callback), nullptr /* data */);
 }
 
 void EventQueue::onLastStrongRef(const void *id) {
diff --git a/services/sensorservice/hidl/SensorManager.cpp b/services/sensorservice/hidl/SensorManager.cpp
index fee6da1..9380600 100644
--- a/services/sensorservice/hidl/SensorManager.cpp
+++ b/services/sensorservice/hidl/SensorManager.cpp
@@ -157,7 +157,7 @@
             JavaVMAttachArgs args{
                 .version = JNI_VERSION_1_2,
                 .name = POLL_THREAD_NAME,
-                .group = NULL
+                .group = nullptr
             };
             JNIEnv* env;
             if (javaVm->AttachCurrentThread(&env, &args) != JNI_OK) {
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 320e11f..b919710 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -26,6 +26,7 @@
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.3",
         "android.hardware.power@1.0",
         "android.hardware.power@1.3",
         "libbase",
@@ -70,6 +71,7 @@
         "android.hardware.graphics.allocator@2.0",
         "android.hardware.graphics.composer@2.1",
         "android.hardware.graphics.composer@2.2",
+        "android.hardware.graphics.composer@2.3",
         "android.hardware.power@1.3",
         "libhidlbase",
         "libhidltransport",
@@ -94,6 +96,7 @@
         "ContainerLayer.cpp",
         "DisplayDevice.cpp",
         "DisplayHardware/ComposerHal.cpp",
+        "DisplayHardware/DisplayIdentification.cpp",
         "DisplayHardware/FramebufferSurface.cpp",
         "DisplayHardware/HWC2.cpp",
         "DisplayHardware/HWComposer.cpp",
@@ -108,6 +111,7 @@
         "FrameTracker.cpp",
         "GpuService.cpp",
         "Layer.cpp",
+        "LayerBE.cpp",
         "LayerProtoHelper.cpp",
         "LayerRejecter.cpp",
         "LayerStats.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 12267ad..37f4b0f 100644
--- a/services/surfaceflinger/BufferLayer.cpp
+++ b/services/surfaceflinger/BufferLayer.cpp
@@ -98,15 +98,13 @@
 }
 
 bool BufferLayer::isProtected() const {
-    const sp<GraphicBuffer>& buffer(getBE().compositionInfo.mBuffer);
-    return (buffer != 0) &&
-            (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+    const sp<GraphicBuffer>& buffer(mActiveBuffer);
+    return (buffer != 0) && (buffer->getUsage() & GRALLOC_USAGE_PROTECTED);
 }
 
 bool BufferLayer::isVisible() const {
     return !(isHiddenByPolicy()) && getAlpha() > 0.0f &&
-            (getBE().compositionInfo.mBuffer != nullptr ||
-             getBE().compositionInfo.hwc.sidebandStream != nullptr);
+            (mActiveBuffer != nullptr || getBE().compositionInfo.hwc.sidebandStream != nullptr);
 }
 
 bool BufferLayer::isFixedSize() const {
@@ -162,7 +160,9 @@
                          bool useIdentityTransform) const {
     ATRACE_CALL();
 
-    if (CC_UNLIKELY(getBE().compositionInfo.mBuffer == 0)) {
+    CompositionInfo& compositionInfo = getBE().compositionInfo;
+
+    if (CC_UNLIKELY(mActiveBuffer == 0)) {
         // the texture has not been created yet, this Layer has
         // in fact never been drawn into. This happens frequently with
         // SurfaceView because the WindowManager can't know when the client
@@ -240,10 +240,10 @@
         }
 
         // Set things up for texturing.
-        mTexture.setDimensions(getBE().compositionInfo.mBuffer->getWidth(),
-                               getBE().compositionInfo.mBuffer->getHeight());
+        mTexture.setDimensions(mActiveBuffer->getWidth(), mActiveBuffer->getHeight());
         mTexture.setFiltering(useFiltering);
         mTexture.setMatrix(textureMatrix);
+        compositionInfo.re.texture = mTexture;
 
         engine.setupLayerTexturing(mTexture);
     } else {
@@ -253,6 +253,23 @@
     engine.disableTexturing();
 }
 
+void BufferLayer::drawNow(const RenderArea& renderArea, bool useIdentityTransform) const {
+    CompositionInfo& compositionInfo = getBE().compositionInfo;
+    auto& engine(mFlinger->getRenderEngine());
+
+    draw(renderArea, useIdentityTransform);
+
+    engine.setupLayerTexturing(compositionInfo.re.texture);
+    engine.setupLayerBlending(compositionInfo.re.preMultipliedAlpha, compositionInfo.re.opaque,
+            false, compositionInfo.re.color);
+    engine.setSourceDataSpace(compositionInfo.hwc.dataspace);
+    engine.setSourceY410BT2020(compositionInfo.re.Y410BT2020);
+    engine.drawMesh(getBE().getMesh());
+    engine.disableBlending();
+    engine.disableTexturing();
+    engine.setSourceY410BT2020(false);
+}
+
 void BufferLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
     mConsumer->setReleaseFence(releaseFence);
 }
@@ -291,12 +308,10 @@
 bool BufferLayer::onPreComposition(nsecs_t refreshStartTime) {
     if (mBufferLatched) {
         Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addPreComposition(mCurrentFrameNumber,
-                                             refreshStartTime);
+        mFrameEventHistory.addPreComposition(mCurrentFrameNumber, refreshStartTime);
     }
     mRefreshPending = false;
-    return mQueuedFrames > 0 || mSidebandStreamChanged ||
-            mAutoRefresh;
+    return mQueuedFrames > 0 || mSidebandStreamChanged || mAutoRefresh;
 }
 bool BufferLayer::onPostComposition(const std::shared_ptr<FenceTime>& glDoneFence,
                                     const std::shared_ptr<FenceTime>& presentFence,
@@ -308,8 +323,8 @@
     // Update mFrameEventHistory.
     {
         Mutex::Autolock lock(mFrameEventHistoryMutex);
-        mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence,
-                                              presentFence, compositorTiming);
+        mFrameEventHistory.addPostComposition(mCurrentFrameNumber, glDoneFence, presentFence,
+                                              compositorTiming);
     }
 
     // Update mFrameTracker.
@@ -331,7 +346,7 @@
     if (presentFence->isValid()) {
         mTimeStats.setPresentFence(layerName, mCurrentFrameNumber, presentFence);
         mFrameTracker.setActualPresentFence(std::shared_ptr<FenceTime>(presentFence));
-    } else {
+    } 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 =
@@ -364,8 +379,7 @@
         return;
     }
 
-    auto releaseFenceTime =
-            std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
+    auto releaseFenceTime = std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
     mReleaseTimeline.updateSignalTimes();
     mReleaseTimeline.push(releaseFenceTime);
 
@@ -418,7 +432,7 @@
     // Capture the old state of the layer for comparisons later
     const State& s(getDrawingState());
     const bool oldOpacity = isOpaque(s);
-    sp<GraphicBuffer> oldBuffer = getBE().compositionInfo.mBuffer;
+    sp<GraphicBuffer> oldBuffer = mActiveBuffer;
 
     if (!allTransactionsSignaled()) {
         mFlinger->signalLayerUpdate();
@@ -431,12 +445,12 @@
     // buffer mode.
     bool queuedBuffer = false;
     LayerRejecter r(mDrawingState, getCurrentState(), recomputeVisibleRegions,
-                    getProducerStickyTransform() != 0, mName.string(),
-                    mOverrideScalingMode, mFreezeGeometryUpdates);
-    status_t updateResult =
-            mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync,
-                                                    &mAutoRefresh, &queuedBuffer,
-                                                    mLastFrameNumberReceived);
+                    getProducerStickyTransform() != 0, mName.string(), mOverrideScalingMode,
+                    getTransformToDisplayInverse(),  mFreezeGeometryUpdates);
+
+    status_t updateResult = mConsumer->updateTexImage(&r, mFlinger->mPrimaryDispSync, &mAutoRefresh,
+                                                      &queuedBuffer, mLastFrameNumberReceived);
+
     if (updateResult == BufferQueue::PRESENT_LATER) {
         // Producer doesn't want buffer to be displayed yet.  Signal a
         // layer update so we check again at the next opportunity.
@@ -496,17 +510,16 @@
 
     // Decrement the queued-frames count.  Signal another event if we
     // have more frames pending.
-    if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) ||
-        mAutoRefresh) {
+    if ((queuedBuffer && android_atomic_dec(&mQueuedFrames) > 1) || mAutoRefresh) {
         mFlinger->signalLayerUpdate();
     }
 
     // update the active buffer
-    getBE().compositionInfo.mBuffer =
-            mConsumer->getCurrentBuffer(&getBE().compositionInfo.mBufferSlot);
-    // replicated in LayerBE until FE/BE is ready to be synchronized
-    mActiveBuffer = getBE().compositionInfo.mBuffer;
-    if (getBE().compositionInfo.mBuffer == nullptr) {
+    mActiveBuffer = mConsumer->getCurrentBuffer(&mActiveBufferSlot);
+    getBE().compositionInfo.mBuffer = mActiveBuffer;
+    getBE().compositionInfo.mBufferSlot = mActiveBufferSlot;
+
+    if (mActiveBuffer == nullptr) {
         // this can only happen if the very first buffer was rejected.
         return outDirtyRegion;
     }
@@ -558,8 +571,7 @@
     Rect crop(mConsumer->getCurrentCrop());
     const uint32_t transform(mConsumer->getCurrentTransform());
     const uint32_t scalingMode(mConsumer->getCurrentScalingMode());
-    if ((crop != mCurrentCrop) ||
-        (transform != mCurrentTransform) ||
+    if ((crop != mCurrentCrop) || (transform != mCurrentTransform) ||
         (scalingMode != mCurrentScalingMode)) {
         mCurrentCrop = crop;
         mCurrentTransform = transform;
@@ -568,15 +580,14 @@
     }
 
     if (oldBuffer != nullptr) {
-        uint32_t bufWidth = getBE().compositionInfo.mBuffer->getWidth();
-        uint32_t bufHeight = getBE().compositionInfo.mBuffer->getHeight();
-        if (bufWidth != uint32_t(oldBuffer->width) ||
-            bufHeight != uint32_t(oldBuffer->height)) {
+        uint32_t bufWidth = mActiveBuffer->getWidth();
+        uint32_t bufHeight = mActiveBuffer->getHeight();
+        if (bufWidth != uint32_t(oldBuffer->width) || bufHeight != uint32_t(oldBuffer->height)) {
             recomputeVisibleRegions = true;
         }
     }
 
-    mCurrentOpacity = getOpacityForFormat(getBE().compositionInfo.mBuffer->format);
+    mCurrentOpacity = getOpacityForFormat(mActiveBuffer->format);
     if (oldOpacity != isOpaque(s)) {
         recomputeVisibleRegions = true;
     }
@@ -615,14 +626,19 @@
     mConsumer->setDefaultBufferSize(w, h);
 }
 
-void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
+void BufferLayer::setPerFrameData(const sp<const DisplayDevice>& display) {
     // Apply this display's projection's viewport to the visible region
     // before giving it to the HWC HAL.
-    const Transform& tr = displayDevice->getTransform();
-    const auto& viewport = displayDevice->getViewport();
+    const Transform& tr = display->getTransform();
+    const auto& viewport = display->getViewport();
     Region visible = tr.transform(visibleRegion.intersect(viewport));
-    auto hwcId = displayDevice->getHwcDisplayId();
-    auto& hwcInfo = getBE().mHwcLayers[hwcId];
+    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) {
@@ -640,7 +656,7 @@
 
     // Sideband layers
     if (getBE().compositionInfo.hwc.sidebandStream.get()) {
-        setCompositionType(hwcId, HWC2::Composition::Sideband);
+        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) {
@@ -654,10 +670,10 @@
     // Device or Cursor layers
     if (mPotentialCursor) {
         ALOGV("[%s] Requesting Cursor composition", mName.string());
-        setCompositionType(hwcId, HWC2::Composition::Cursor);
+        setCompositionType(displayId, HWC2::Composition::Cursor);
     } else {
         ALOGV("[%s] Requesting Device composition", mName.string());
-        setCompositionType(hwcId, HWC2::Composition::Device);
+        setCompositionType(displayId, HWC2::Composition::Device);
     }
 
     ALOGV("setPerFrameData: dataspace = %d", mCurrentDataSpace);
@@ -668,7 +684,7 @@
     }
 
     const HdrMetadata& metadata = mConsumer->getCurrentHdrMetadata();
-    error = hwcLayer->setPerFrameMetadata(displayDevice->getSupportedPerFrameMetadata(), metadata);
+    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));
@@ -676,8 +692,7 @@
 
     uint32_t hwcSlot = 0;
     sp<GraphicBuffer> hwcBuffer;
-    hwcInfo.bufferCache.getHwcBuffer(getBE().compositionInfo.mBufferSlot,
-                                     getBE().compositionInfo.mBuffer, &hwcSlot, &hwcBuffer);
+    hwcInfo.bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot, &hwcBuffer);
 
     auto acquireFence = mConsumer->getCurrentFence();
     error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
@@ -691,7 +706,7 @@
 bool BufferLayer::isOpaque(const Layer::State& s) const {
     // if we don't have a buffer or sidebandStream yet, we're translucent regardless of the
     // layer's opaque flag.
-    if ((getBE().compositionInfo.hwc.sidebandStream == nullptr) && (getBE().compositionInfo.mBuffer == nullptr)) {
+    if ((getBE().compositionInfo.hwc.sidebandStream == nullptr) && (mActiveBuffer == nullptr)) {
         return false;
     }
 
@@ -720,8 +735,9 @@
         mProducer->setMaxDequeuedBufferCount(2);
     }
 
-    const sp<const DisplayDevice> hw(mFlinger->getDefaultDisplayDevice());
-    updateTransformHint(hw);
+    if (const auto display = mFlinger->getDefaultDisplayDevice()) {
+        updateTransformHint(display);
+    }
 }
 
 // ---------------------------------------------------------------------------
@@ -743,8 +759,7 @@
 
         // Ensure that callbacks are handled in order
         while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
-            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
-                                                               ms2ns(500));
+            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
             if (result != NO_ERROR) {
                 ALOGE("[%s] Timed out waiting on callback", mName.string());
             }
@@ -767,8 +782,7 @@
 
         // Ensure that callbacks are handled in order
         while (item.mFrameNumber != mLastFrameNumberReceived + 1) {
-            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock,
-                                                               ms2ns(500));
+            status_t result = mQueueItemCondition.waitRelative(mQueueItemLock, ms2ns(500));
             if (result != NO_ERROR) {
                 ALOGE("[%s] Timed out waiting on callback", mName.string());
             }
@@ -939,8 +953,7 @@
         // able to be latched. To avoid this, grab this buffer anyway.
         return true;
     }
-    return mQueueItems[0].mFenceTime->getSignalTime() !=
-            Fence::SIGNAL_TIME_PENDING;
+    return mQueueItems[0].mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
 }
 
 uint32_t BufferLayer::getEffectiveScalingMode() const {
diff --git a/services/surfaceflinger/BufferLayer.h b/services/surfaceflinger/BufferLayer.h
index bf0ca69..0886f17 100644
--- a/services/surfaceflinger/BufferLayer.h
+++ b/services/surfaceflinger/BufferLayer.h
@@ -101,6 +101,7 @@
      */
     void onDraw(const RenderArea& renderArea, const Region& clip,
                 bool useIdentityTransform) const override;
+    void drawNow(const RenderArea& renderArea, bool useIdentityTransform) const;
 
     void onLayerDisplayed(const sp<Fence>& releaseFence) override;
 
@@ -131,7 +132,7 @@
 
     bool isHdrY410() const override;
 
-    void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+    void setPerFrameData(const sp<const DisplayDevice>& display) override;
 
     bool isOpaque(const Layer::State& s) const override;
 
diff --git a/services/surfaceflinger/BufferLayerConsumer.cpp b/services/surfaceflinger/BufferLayerConsumer.cpp
index 87333d0..d231790 100644
--- a/services/surfaceflinger/BufferLayerConsumer.cpp
+++ b/services/surfaceflinger/BufferLayerConsumer.cpp
@@ -280,14 +280,6 @@
     return NO_ERROR;
 }
 
-bool BufferLayerConsumer::canUseImageCrop(const Rect& crop) const {
-    // If the crop rect is not at the origin, we can't set the crop on the
-    // EGLImage because that's not allowed by the EGL_ANDROID_image_crop
-    // extension.  In the future we can add a layered extension that
-    // removes this restriction if there is hardware that can support it.
-    return mRE.supportsImageCrop() && crop.left == 0 && crop.top == 0;
-}
-
 status_t BufferLayerConsumer::updateAndReleaseLocked(const BufferItem& item,
                                                      PendingRelease* pendingRelease) {
     status_t err = NO_ERROR;
@@ -365,8 +357,7 @@
         return NO_INIT;
     }
 
-    const Rect& imageCrop = canUseImageCrop(mCurrentCrop) ? mCurrentCrop : Rect::EMPTY_RECT;
-    status_t err = mCurrentTextureImage->createIfNeeded(imageCrop);
+    status_t err = mCurrentTextureImage->createIfNeeded();
     if (err != NO_ERROR) {
         BLC_LOGW("bindTextureImage: can't create image on slot=%d", mCurrentTexture);
         mRE.bindExternalTextureImage(mTexName, *mRE.createImage());
@@ -435,9 +426,8 @@
         BLC_LOGD("computeCurrentTransformMatrixLocked: "
                  "mCurrentTextureImage is nullptr");
     }
-    const Rect& cropRect = canUseImageCrop(mCurrentCrop) ? Rect::EMPTY_RECT : mCurrentCrop;
-    GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf, cropRect, mCurrentTransform,
-                                       mFilteringEnabled);
+    GLConsumer::computeTransformMatrix(mCurrentTransformMatrix, buf, mCurrentCrop,
+                                       mCurrentTransform, mFilteringEnabled);
 }
 
 nsecs_t BufferLayerConsumer::getTimestamp() {
@@ -615,23 +605,12 @@
 
 BufferLayerConsumer::Image::~Image() = default;
 
-status_t BufferLayerConsumer::Image::createIfNeeded(const Rect& imageCrop) {
-    const int32_t cropWidth = imageCrop.width();
-    const int32_t cropHeight = imageCrop.height();
-    if (mCreated && mCropWidth == cropWidth && mCropHeight == cropHeight) {
-        return OK;
-    }
+status_t BufferLayerConsumer::Image::createIfNeeded() {
+    if (mCreated) return OK;
 
     mCreated = mImage->setNativeWindowBuffer(mGraphicBuffer->getNativeBuffer(),
-                                             mGraphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED,
-                                             cropWidth, cropHeight);
-    if (mCreated) {
-        mCropWidth = cropWidth;
-        mCropHeight = cropHeight;
-    } else {
-        mCropWidth = 0;
-        mCropHeight = 0;
-
+                                             mGraphicBuffer->getUsage() & GRALLOC_USAGE_PROTECTED);
+    if (!mCreated) {
         const sp<GraphicBuffer>& buffer = mGraphicBuffer;
         ALOGE("Failed to create image. size=%ux%u st=%u usage=%#" PRIx64 " fmt=%d",
               buffer->getWidth(), buffer->getHeight(), buffer->getStride(), buffer->getUsage(),
diff --git a/services/surfaceflinger/BufferLayerConsumer.h b/services/surfaceflinger/BufferLayerConsumer.h
index f81cdb1..943b8a8 100644
--- a/services/surfaceflinger/BufferLayerConsumer.h
+++ b/services/surfaceflinger/BufferLayerConsumer.h
@@ -228,9 +228,8 @@
         Image(const Image& rhs) = delete;
         Image& operator=(const Image& rhs) = delete;
 
-        // createIfNeeded creates an RE::Image if required (we haven't created
-        // one yet, or the crop-rect has changed).
-        status_t createIfNeeded(const Rect& imageCrop);
+        // createIfNeeded creates an RE::Image if we haven't created one yet.
+        status_t createIfNeeded();
 
         const sp<GraphicBuffer>& graphicBuffer() { return mGraphicBuffer; }
         const native_handle* graphicBufferHandle() {
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 512564c..10075ae 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -46,27 +46,42 @@
                         bool useIdentityTransform) const {
     half4 color = getColor();
     if (color.a > 0) {
-        Mesh mesh(Mesh::TRIANGLE_FAN, 4, 2);
-        computeGeometry(renderArea, mesh, useIdentityTransform);
-        auto& engine(mFlinger->getRenderEngine());
-        engine.setupLayerBlending(getPremultipledAlpha(), false /* opaque */,
-                                  true /* disableTexture */, color);
-        engine.drawMesh(mesh);
-        engine.disableBlending();
+        computeGeometry(renderArea, getBE().mMesh, useIdentityTransform);
+        getBE().compositionInfo.re.preMultipliedAlpha = getPremultipledAlpha();
+        getBE().compositionInfo.re.opaque = false;
+        getBE().compositionInfo.re.disableTexture = true;
+        getBE().compositionInfo.re.color = color;
     }
 }
 
-bool ColorLayer::isVisible() const {
-    const Layer::State& s(getDrawingState());
-    return !isHiddenByPolicy() && s.color.a;
+void ColorLayer::drawNow(const RenderArea& renderArea, bool useIdentityTransform) const {
+    CompositionInfo& compositionInfo = getBE().compositionInfo;
+    auto& engine(mFlinger->getRenderEngine());
+
+    draw(renderArea, useIdentityTransform);
+
+    engine.setupLayerBlending(compositionInfo.re.preMultipliedAlpha, compositionInfo.re.opaque,
+            compositionInfo.re.disableTexture, compositionInfo.re.color);
+    engine.setSourceDataSpace(compositionInfo.hwc.dataspace);
+    engine.drawMesh(getBE().getMesh());
+    engine.disableBlending();
 }
 
-void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& displayDevice) {
-    const Transform& tr = displayDevice->getTransform();
-    const auto& viewport = displayDevice->getViewport();
+bool ColorLayer::isVisible() const {
+    return !isHiddenByPolicy() && getAlpha() > 0.0f;
+}
+
+void ColorLayer::setPerFrameData(const sp<const DisplayDevice>& display) {
+    const Transform& tr = display->getTransform();
+    const auto& viewport = display->getViewport();
     Region visible = tr.transform(visibleRegion.intersect(viewport));
-    auto hwcId = displayDevice->getHwcDisplayId();
-    auto& hwcInfo = getBE().mHwcLayers[hwcId];
+    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) {
@@ -75,7 +90,7 @@
         visible.dump(LOG_TAG);
     }
 
-    setCompositionType(hwcId, HWC2::Composition::SolidColor);
+    setCompositionType(displayId, HWC2::Composition::SolidColor);
 
     error = hwcLayer->setDataspace(mCurrentDataSpace);
     if (error != HWC2::Error::None) {
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 0cde398..8417135 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -32,9 +32,13 @@
     virtual const char* getTypeId() const { return "ColorLayer"; }
     virtual void onDraw(const RenderArea& renderArea, const Region& clip,
                         bool useIdentityTransform) const;
+    void drawNow(const RenderArea& , bool ) const;
     bool isVisible() const override;
 
-    void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+    void setPerFrameData(const sp<const DisplayDevice>& display) override;
+
+protected:
+    FloatRect computeCrop(const sp<const DisplayDevice>& /*display*/) const override { return {}; }
 };
 
 } // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index f259d93..320c0df 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -30,6 +30,8 @@
 
 void ContainerLayer::onDraw(const RenderArea&, const Region& /* clip */, bool) const {}
 
+void ContainerLayer::drawNow(const RenderArea&, bool) const {}
+
 bool ContainerLayer::isVisible() const {
     return !isHiddenByPolicy();
 }
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index b352b96..29a5c3a 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -32,9 +32,10 @@
     const char* getTypeId() const override { return "ContainerLayer"; }
     void onDraw(const RenderArea& renderArea, const Region& clip,
                 bool useIdentityTransform) const override;
+    void drawNow(const RenderArea& renderArea, bool useIdentityTransform) const override;
     bool isVisible() const override;
 
-    void setPerFrameData(const sp<const DisplayDevice>& displayDevice) override;
+    void setPerFrameData(const sp<const DisplayDevice>& display) override;
 
     bool isCreatedFromMainThread() const override { return true; }
 };
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 37dc27d..829b53d 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -28,7 +28,6 @@
 #include <utils/String8.h>
 #include <utils/Thread.h>
 #include <utils/Trace.h>
-#include <utils/Vector.h>
 
 #include <ui/FenceTime.h>
 
@@ -94,7 +93,7 @@
         nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC);
 
         while (true) {
-            Vector<CallbackInvocation> callbackInvocations;
+            std::vector<CallbackInvocation> callbackInvocations;
 
             nsecs_t targetTime = 0;
 
@@ -187,7 +186,7 @@
         // allowing any past events to fire
         listener.mLastEventTime = systemTime() - mPeriod / 2 + mPhase - mWakeupLatency;
 
-        mEventListeners.push(listener);
+        mEventListeners.push_back(listener);
 
         mCond.signal();
 
@@ -198,9 +197,10 @@
         if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
 
-        for (size_t i = 0; i < mEventListeners.size(); i++) {
-            if (mEventListeners[i].mCallback == callback) {
-                mEventListeners.removeAt(i);
+        for (std::vector<EventListener>::iterator it = mEventListeners.begin();
+             it != mEventListeners.end(); ++it) {
+            if (it->mCallback == callback) {
+                mEventListeners.erase(it);
                 mCond.signal();
                 return NO_ERROR;
             }
@@ -213,11 +213,10 @@
         if (kTraceDetailedInfo) ATRACE_CALL();
         Mutex::Autolock lock(mMutex);
 
-        for (size_t i = 0; i < mEventListeners.size(); i++) {
-            if (mEventListeners[i].mCallback == callback) {
-                EventListener& listener = mEventListeners.editItemAt(i);
-                const nsecs_t oldPhase = listener.mPhase;
-                listener.mPhase = phase;
+        for (auto& eventListener : mEventListeners) {
+            if (eventListener.mCallback == callback) {
+                const nsecs_t oldPhase = eventListener.mPhase;
+                eventListener.mPhase = phase;
 
                 // Pretend that the last time this event was handled at the same frame but with the
                 // new offset to allow for a seamless offset change without double-firing or
@@ -228,7 +227,7 @@
                 } else if (diff < -mPeriod / 2) {
                     diff += mPeriod;
                 }
-                listener.mLastEventTime -= diff;
+                eventListener.mLastEventTime -= diff;
                 mCond.signal();
                 return NO_ERROR;
             }
@@ -237,14 +236,6 @@
         return BAD_VALUE;
     }
 
-    // This method is only here to handle the !SurfaceFlinger::hasSyncFramework
-    // case.
-    bool hasAnyEventListeners() {
-        if (kTraceDetailedInfo) ATRACE_CALL();
-        Mutex::Autolock lock(mMutex);
-        return !mEventListeners.empty();
-    }
-
 private:
     struct EventListener {
         const char* mName;
@@ -274,23 +265,23 @@
         return nextEventTime;
     }
 
-    Vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
+    std::vector<CallbackInvocation> gatherCallbackInvocationsLocked(nsecs_t now) {
         if (kTraceDetailedInfo) ATRACE_CALL();
         ALOGV("[%s] gatherCallbackInvocationsLocked @ %" PRId64, mName, ns2us(now));
 
-        Vector<CallbackInvocation> callbackInvocations;
+        std::vector<CallbackInvocation> callbackInvocations;
         nsecs_t onePeriodAgo = now - mPeriod;
 
-        for (size_t i = 0; i < mEventListeners.size(); i++) {
-            nsecs_t t = computeListenerNextEventTimeLocked(mEventListeners[i], onePeriodAgo);
+        for (auto& eventListener : mEventListeners) {
+            nsecs_t t = computeListenerNextEventTimeLocked(eventListener, onePeriodAgo);
 
             if (t < now) {
                 CallbackInvocation ci;
-                ci.mCallback = mEventListeners[i].mCallback;
+                ci.mCallback = eventListener.mCallback;
                 ci.mEventTime = t;
-                ALOGV("[%s] [%s] Preparing to fire", mName, mEventListeners[i].mName);
-                callbackInvocations.push(ci);
-                mEventListeners.editItemAt(i).mLastEventTime = t;
+                ALOGV("[%s] [%s] Preparing to fire", mName, eventListener.mName);
+                callbackInvocations.push_back(ci);
+                eventListener.mLastEventTime = t;
             }
         }
 
@@ -348,7 +339,7 @@
         return t;
     }
 
-    void fireCallbackInvocations(const Vector<CallbackInvocation>& callbacks) {
+    void fireCallbackInvocations(const std::vector<CallbackInvocation>& callbacks) {
         if (kTraceDetailedInfo) ATRACE_CALL();
         for (size_t i = 0; i < callbacks.size(); i++) {
             callbacks[i].mCallback->onDispSyncEvent(callbacks[i].mEventTime);
@@ -366,7 +357,7 @@
 
     int64_t mFrameNumber;
 
-    Vector<EventListener> mEventListeners;
+    std::vector<EventListener> mEventListeners;
 
     Mutex mMutex;
     Condition mCond;
@@ -408,22 +399,18 @@
     reset();
     beginResync();
 
-    if (kTraceDetailedInfo) {
-        // If we're not getting present fences then the ZeroPhaseTracer
-        // would prevent HW vsync event from ever being turned off.
-        // Even if we're just ignoring the fences, the zero-phase tracing is
-        // not needed because any time there is an event registered we will
-        // turn on the HW vsync events.
-        if (!mIgnorePresentFences && kEnableZeroPhaseTracer) {
-            mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>();
-            addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get());
-        }
+    if (kTraceDetailedInfo && kEnableZeroPhaseTracer) {
+        mZeroPhaseTracer = std::make_unique<ZeroPhaseTracer>();
+        addEventListener("ZeroPhaseTracer", 0, mZeroPhaseTracer.get());
     }
 }
 
 void DispSync::reset() {
     Mutex::Autolock lock(mMutex);
+    resetLocked();
+}
 
+void DispSync::resetLocked() {
     mPhase = 0;
     mReferenceTime = 0;
     mModelUpdated = false;
@@ -436,6 +423,10 @@
 bool DispSync::addPresentFence(const std::shared_ptr<FenceTime>& fenceTime) {
     Mutex::Autolock lock(mMutex);
 
+    if (mIgnorePresentFences) {
+        return true;
+    }
+
     mPresentFences[mPresentSampleOffset] = fenceTime;
     mPresentSampleOffset = (mPresentSampleOffset + 1) % NUM_PRESENT_SAMPLES;
     mNumResyncSamplesSincePresent = 0;
@@ -481,12 +472,10 @@
     }
 
     if (mIgnorePresentFences) {
-        // If we don't have the sync framework we will never have
-        // addPresentFence called.  This means we have no way to know whether
+        // If we're ignoring the present fences we have no way to know whether
         // or not we're synchronized with the HW vsyncs, so we just request
-        // that the HW vsync events be turned on whenever we need to generate
-        // SW vsync events.
-        return mThread->hasAnyEventListeners();
+        // that the HW vsync events be turned on.
+        return true;
     }
 
     // Check against kErrorThreshold / 2 to add some hysteresis before having to
@@ -660,6 +649,14 @@
     return (((now - phase) / mPeriod) + periodOffset + 1) * mPeriod + phase;
 }
 
+void DispSync::setIgnorePresentFences(bool ignore) {
+    Mutex::Autolock lock(mMutex);
+    if (mIgnorePresentFences != ignore) {
+        mIgnorePresentFences = ignore;
+        resetLocked();
+    }
+}
+
 void DispSync::dump(String8& result) const {
     Mutex::Autolock lock(mMutex);
     result.appendFormat("present fences are %s\n", mIgnorePresentFences ? "ignored" : "used");
diff --git a/services/surfaceflinger/DispSync.h b/services/surfaceflinger/DispSync.h
index 077256a..c00c161 100644
--- a/services/surfaceflinger/DispSync.h
+++ b/services/surfaceflinger/DispSync.h
@@ -124,12 +124,21 @@
     // the refresh after next. etc.
     nsecs_t computeNextRefresh(int periodOffset) const;
 
+    // In certain situations the present fences aren't a good indicator of vsync
+    // time, e.g. when vr flinger is active, or simply aren't available,
+    // e.g. when the sync framework isn't present. Use this method to toggle
+    // whether or not DispSync ignores present fences. If present fences are
+    // ignored, DispSync will always ask for hardware vsync events by returning
+    // true from addPresentFence() and addResyncSample().
+    void setIgnorePresentFences(bool ignore);
+
     // dump appends human-readable debug info to the result string.
     void dump(String8& result) const;
 
 private:
     void updateModelLocked();
     void updateErrorLocked();
+    void resetLocked();
     void resetErrorLocked();
 
     enum { MAX_RESYNC_SAMPLES = 32 };
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index db095a5..4d2b0ea 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -216,7 +216,7 @@
 DisplayDevice::DisplayDevice(
         const sp<SurfaceFlinger>& flinger,
         DisplayType type,
-        int32_t hwcId,
+        int32_t id,
         bool isSecure,
         const wp<IBinder>& displayToken,
         const sp<ANativeWindow>& nativeWindow,
@@ -232,7 +232,7 @@
     : lastCompositionHadVisibleLayers(false),
       mFlinger(flinger),
       mType(type),
-      mHwcDisplayId(hwcId),
+      mId(id),
       mDisplayToken(displayToken),
       mNativeWindow(nativeWindow),
       mDisplaySurface(displaySurface),
@@ -301,9 +301,9 @@
 DisplayDevice::~DisplayDevice() = default;
 
 void DisplayDevice::disconnect(HWComposer& hwc) {
-    if (mHwcDisplayId >= 0) {
-        hwc.disconnectDisplay(mHwcDisplayId);
-        mHwcDisplayId = -1;
+    if (mId >= 0) {
+        hwc.disconnectDisplay(mId);
+        mId = -1;
     }
 }
 
@@ -319,8 +319,8 @@
     return mDisplayHeight;
 }
 
-void DisplayDevice::setDisplayName(const String8& displayName) {
-    if (!displayName.isEmpty()) {
+void DisplayDevice::setDisplayName(const std::string& displayName) {
+    if (!displayName.empty()) {
         // never override the name with an empty name
         mDisplayName = displayName;
     }
@@ -347,8 +347,8 @@
     }
 
     DisplaySurface::CompositionType compositionType;
-    bool hasClient = hwc.hasClientComposition(mHwcDisplayId);
-    bool hasDevice = hwc.hasDeviceComposition(mHwcDisplayId);
+    bool hasClient = hwc.hasClientComposition(mId);
+    bool hasDevice = hwc.hasDeviceComposition(mId);
     if (hasClient && hasDevice) {
         compositionType = DisplaySurface::COMPOSITION_MIXED;
     } else if (hasClient) {
@@ -365,14 +365,13 @@
 }
 
 void DisplayDevice::swapBuffers(HWComposer& hwc) const {
-    if (hwc.hasClientComposition(mHwcDisplayId) || hwc.hasFlipClientTargetRequest(mHwcDisplayId)) {
+    if (hwc.hasClientComposition(mId) || hwc.hasFlipClientTargetRequest(mId)) {
         mSurface->swapBuffers();
     }
 
     status_t result = mDisplaySurface->advanceFrame();
     if (result != NO_ERROR) {
-        ALOGE("[%s] failed pushing new frame to HWC: %d",
-                mDisplayName.string(), result);
+        ALOGE("[%s] failed pushing new frame to HWC: %d", mDisplayName.c_str(), result);
     }
 }
 
@@ -437,8 +436,8 @@
     return mPowerMode;
 }
 
-bool DisplayDevice::isDisplayOn() const {
-    return (mPowerMode != HWC_POWER_MODE_OFF);
+bool DisplayDevice::isPoweredOn() const {
+    return mPowerMode != HWC_POWER_MODE_OFF;
 }
 
 // ----------------------------------------------------------------------------
@@ -631,7 +630,7 @@
     }
 
     mOrientation = orientation;
-    if (mType == DisplayType::DISPLAY_PRIMARY) {
+    if (isPrimary()) {
         uint32_t transform = 0;
         switch (mOrientation) {
             case DisplayState::eOrientationDefault:
@@ -660,11 +659,11 @@
 void DisplayDevice::dump(String8& result) const {
     const Transform& tr(mGlobalTransform);
     ANativeWindow* const window = mNativeWindow.get();
-    result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.string());
-    result.appendFormat("   type=%x, hwcId=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p "
+    result.appendFormat("+ DisplayDevice: %s\n", mDisplayName.c_str());
+    result.appendFormat("   type=%x, ID=%d, layerStack=%u, (%4dx%4d), ANativeWindow=%p "
                         "(%d:%d:%d:%d), orient=%2d (type=%08x), "
                         "flips=%u, isSecure=%d, powerMode=%d, activeConfig=%d, numLayers=%zu\n",
-                        mType, mHwcDisplayId, mLayerStack, mDisplayWidth, mDisplayHeight, window,
+                        mType, mId, mLayerStack, mDisplayWidth, mDisplayHeight, window,
                         mSurface->queryRedSize(), mSurface->queryGreenSize(),
                         mSurface->queryBlueSize(), mSurface->queryAlphaSize(), mOrientation,
                         tr.getType(), getPageFlipCount(), mIsSecure, mPowerMode, mActiveConfig,
@@ -704,7 +703,7 @@
     const Dataspace dataspace = colorModeToDataspace(mode);
     const Dataspace hwcDataspace = colorModeToDataspace(hwcColorMode);
 
-    ALOGV("DisplayDevice %d/%d: map (%s, %s) to (%s, %s, %s)", mType, mHwcDisplayId,
+    ALOGV("DisplayDevice %d/%d: map (%s, %s) to (%s, %s, %s)", mType, mId,
           dataspaceDetails(static_cast<android_dataspace_t>(dataspace)).c_str(),
           decodeRenderIntent(intent).c_str(),
           dataspaceDetails(static_cast<android_dataspace_t>(hwcDataspace)).c_str(),
@@ -791,18 +790,6 @@
     }
 }
 
-std::atomic<int32_t> DisplayDeviceState::nextDisplayId(1);
-
-DisplayDeviceState::DisplayDeviceState(DisplayDevice::DisplayType type, bool isSecure)
-    : type(type),
-      layerStack(DisplayDevice::NO_LAYER_STACK),
-      orientation(0),
-      width(0),
-      height(0),
-      isSecure(isSecure)
-{
-    viewport.makeInvalid();
-    frame.makeInvalid();
-}
+std::atomic<int32_t> DisplayDeviceState::sNextSequenceId(1);
 
 }  // namespace android
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 6c3bd91..f440d29 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -39,6 +39,7 @@
 #include "RenderEngine/Surface.h"
 
 #include <memory>
+#include <string>
 
 struct ANativeWindow;
 
@@ -80,7 +81,7 @@
     DisplayDevice(
             const sp<SurfaceFlinger>& flinger,
             DisplayType type,
-            int32_t hwcId,
+            int32_t id,
             bool isSecure,
             const wp<IBinder>& displayToken,
             const sp<ANativeWindow>& nativeWindow,
@@ -134,7 +135,8 @@
     uint32_t                getLayerStack() const { return mLayerStack; }
     int32_t                 getDisplayType() const { return mType; }
     bool                    isPrimary() const { return mType == DISPLAY_PRIMARY; }
-    int32_t                 getHwcDisplayId() const { return mHwcDisplayId; }
+    bool                    isVirtual() const { return mType == DISPLAY_VIRTUAL; }
+    int32_t                 getId() const { return mId; }
     const wp<IBinder>&      getDisplayToken() const { return mDisplayToken; }
 
     int32_t getSupportedPerFrameMetadata() const { return mSupportedPerFrameMetadata; }
@@ -179,8 +181,8 @@
     }
     inline Rect bounds() const { return getBounds(); }
 
-    void setDisplayName(const String8& displayName);
-    const String8& getDisplayName() const { return mDisplayName; }
+    void setDisplayName(const std::string& displayName);
+    const std::string& getDisplayName() const { return mDisplayName; }
 
     bool makeCurrent() const;
     void setViewportAndProjection() const;
@@ -192,7 +194,7 @@
      */
     int getPowerMode() const;
     void setPowerMode(int mode);
-    bool isDisplayOn() const;
+    bool isPoweredOn() const;
 
     ui::ColorMode getActiveColorMode() const;
     void setActiveColorMode(ui::ColorMode mode);
@@ -224,7 +226,7 @@
      */
     sp<SurfaceFlinger> mFlinger;
     DisplayType mType;
-    int32_t mHwcDisplayId;
+    int32_t mId;
     wp<IBinder> mDisplayToken;
 
     // ANativeWindow this display is rendering into
@@ -235,7 +237,7 @@
     int             mDisplayWidth;
     int             mDisplayHeight;
     mutable uint32_t mPageFlipCount;
-    String8         mDisplayName;
+    std::string     mDisplayName;
     bool            mIsSecure;
 
     /*
@@ -313,15 +315,9 @@
 };
 
 struct DisplayDeviceState {
-    DisplayDeviceState() = default;
-    DisplayDeviceState(DisplayDevice::DisplayType type, bool isSecure);
+    bool isVirtual() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; }
 
-    bool isValid() const { return type >= 0; }
-    bool isMainDisplay() const { return type == DisplayDevice::DISPLAY_PRIMARY; }
-    bool isVirtualDisplay() const { return type >= DisplayDevice::DISPLAY_VIRTUAL; }
-
-    static std::atomic<int32_t> nextDisplayId;
-    int32_t displayId = nextDisplayId++;
+    int32_t sequenceId = sNextSequenceId++;
     DisplayDevice::DisplayType type = DisplayDevice::DISPLAY_ID_INVALID;
     sp<IGraphicBufferProducer> surface;
     uint32_t layerStack = DisplayDevice::NO_LAYER_STACK;
@@ -330,8 +326,11 @@
     uint8_t orientation = 0;
     uint32_t width = 0;
     uint32_t height = 0;
-    String8 displayName;
+    std::string displayName;
     bool isSecure = false;
+
+private:
+    static std::atomic<int32_t> sNextSequenceId;
 };
 
 class DisplayRenderArea : public RenderArea {
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
index 37ba433..741eb7c 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.cpp
@@ -22,7 +22,6 @@
 
 #include "ComposerHal.h"
 
-#include <android/hardware/graphics/composer/2.2/IComposer.h>
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
 #include <gui/BufferQueue.h>
 #include <hidl/HidlTransportUtils.h>
@@ -172,22 +171,31 @@
         LOG_ALWAYS_FATAL("failed to get hwcomposer service");
     }
 
-    mComposer->createClient(
-            [&](const auto& tmpError, const auto& tmpClient)
-            {
-                if (tmpError == Error::NONE) {
-                    mClient = tmpClient;
-                }
-            });
-    if (mClient == nullptr) {
-        LOG_ALWAYS_FATAL("failed to create composer client");
+    if (sp<IComposer> composer_2_3 = IComposer::castFrom(mComposer)) {
+        composer_2_3->createClient_2_3([&](const auto& tmpError, const auto& tmpClient) {
+            if (tmpError == Error::NONE) {
+                mClient = tmpClient;
+                mClient_2_2 = tmpClient;
+                mClient_2_3 = tmpClient;
+            }
+        });
+    } else {
+        mComposer->createClient([&](const auto& tmpError, const auto& tmpClient) {
+            if (tmpError != Error::NONE) {
+                return;
+            }
+
+            mClient = tmpClient;
+            if (sp<V2_2::IComposer> composer_2_2 = V2_2::IComposer::castFrom(mComposer)) {
+                mClient_2_2 = V2_2::IComposerClient::castFrom(mClient);
+                LOG_ALWAYS_FATAL_IF(mClient_2_2 == nullptr,
+                                    "IComposer 2.2 did not return IComposerClient 2.2");
+            }
+        });
     }
 
-    // 2.2 support is optional
-    sp<IComposer> composer_2_2 = IComposer::castFrom(mComposer);
-    if (composer_2_2 != nullptr) {
-        mClient_2_2 = IComposerClient::castFrom(mClient);
-        LOG_ALWAYS_FATAL_IF(mClient_2_2 == nullptr, "IComposer 2.2 did not return IComposerClient 2.2");
+    if (mClient == nullptr) {
+        LOG_ALWAYS_FATAL("failed to create composer client");
     }
 
     if (mIsUsingVrComposer) {
@@ -897,23 +905,25 @@
     return Error::NONE;
 }
 
-Error Composer::getPerFrameMetadataKeys(
-        Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) {
+std::vector<IComposerClient::PerFrameMetadataKey> Composer::getPerFrameMetadataKeys(
+        Display display) {
+    std::vector<IComposerClient::PerFrameMetadataKey>  keys;
     if (!mClient_2_2) {
-        return Error::UNSUPPORTED;
+        return keys;
     }
 
     Error error = kDefaultError;
     mClient_2_2->getPerFrameMetadataKeys(display, [&](const auto& tmpError, const auto& tmpKeys) {
         error = tmpError;
         if (error != Error::NONE) {
+            ALOGW("getPerFrameMetadataKeys failed with %d", tmpError);
             return;
         }
 
-        *outKeys = tmpKeys;
+        keys = tmpKeys;
     });
 
-    return error;
+    return keys;
 }
 
 Error Composer::getRenderIntents(Display display, ColorMode colorMode,
@@ -957,6 +967,30 @@
     return error;
 }
 
+// Composer HAL 2.3
+
+Error Composer::getDisplayIdentificationData(Display display, uint8_t* outPort,
+                                             std::vector<uint8_t>* outData) {
+    if (!mClient_2_3) {
+        return Error::UNSUPPORTED;
+    }
+
+    Error error = kDefaultError;
+    mClient_2_3->getDisplayIdentificationData(display,
+                                              [&](const auto& tmpError, const auto& tmpPort,
+                                                  const auto& tmpData) {
+                                                  error = tmpError;
+                                                  if (error != Error::NONE) {
+                                                      return;
+                                                  }
+
+                                                  *outPort = tmpPort;
+                                                  *outData = tmpData;
+                                              });
+
+    return error;
+}
+
 CommandReader::~CommandReader()
 {
     resetData();
diff --git a/services/surfaceflinger/DisplayHardware/ComposerHal.h b/services/surfaceflinger/DisplayHardware/ComposerHal.h
index beee539..60b0f72 100644
--- a/services/surfaceflinger/DisplayHardware/ComposerHal.h
+++ b/services/surfaceflinger/DisplayHardware/ComposerHal.h
@@ -25,8 +25,8 @@
 
 #include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
 #include <android/hardware/graphics/common/1.1/types.h>
-#include <android/hardware/graphics/composer/2.2/IComposer.h>
-#include <android/hardware/graphics/composer/2.2/IComposerClient.h>
+#include <android/hardware/graphics/composer/2.3/IComposer.h>
+#include <android/hardware/graphics/composer/2.3/IComposerClient.h>
 #include <composer-command-buffer/2.2/ComposerCommandBuffer.h>
 #include <gui/HdrMetadata.h>
 #include <math/mat4.h>
@@ -43,6 +43,7 @@
 
 namespace V2_1 = hardware::graphics::composer::V2_1;
 namespace V2_2 = hardware::graphics::composer::V2_2;
+namespace V2_3 = hardware::graphics::composer::V2_3;
 
 using types::V1_0::ColorTransform;
 using types::V1_0::Hdr;
@@ -61,8 +62,9 @@
 
 using V2_2::CommandReaderBase;
 using V2_2::CommandWriterBase;
-using V2_2::IComposer;
-using V2_2::IComposerClient;
+
+using V2_3::IComposer;
+using V2_3::IComposerClient;
 
 using PerFrameMetadata = IComposerClient::PerFrameMetadata;
 using PerFrameMetadataKey = IComposerClient::PerFrameMetadataKey;
@@ -180,11 +182,15 @@
     virtual Error setLayerPerFrameMetadata(
             Display display, Layer layer,
             const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) = 0;
-    virtual Error getPerFrameMetadataKeys(
-            Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) = 0;
+    virtual std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys(
+            Display display) = 0;
     virtual Error getRenderIntents(Display display, ColorMode colorMode,
             std::vector<RenderIntent>* outRenderIntents) = 0;
     virtual Error getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) = 0;
+
+    // Composer HAL 2.3
+    virtual Error getDisplayIdentificationData(Display display, uint8_t* outPort,
+                                               std::vector<uint8_t>* outData) = 0;
 };
 
 namespace impl {
@@ -374,12 +380,16 @@
     Error setLayerPerFrameMetadata(
             Display display, Layer layer,
             const std::vector<IComposerClient::PerFrameMetadata>& perFrameMetadatas) override;
-    Error getPerFrameMetadataKeys(
-            Display display, std::vector<IComposerClient::PerFrameMetadataKey>* outKeys) override;
+    std::vector<IComposerClient::PerFrameMetadataKey> getPerFrameMetadataKeys(
+            Display display) override;
     Error getRenderIntents(Display display, ColorMode colorMode,
             std::vector<RenderIntent>* outRenderIntents) override;
     Error getDataspaceSaturationMatrix(Dataspace dataspace, mat4* outMatrix) override;
 
+    // Composer HAL 2.3
+    Error getDisplayIdentificationData(Display display, uint8_t* outPort,
+                                       std::vector<uint8_t>* outData) override;
+
 private:
     class CommandWriter : public CommandWriterBase {
     public:
@@ -405,7 +415,8 @@
     sp<V2_1::IComposer> mComposer;
 
     sp<V2_1::IComposerClient> mClient;
-    sp<IComposerClient> mClient_2_2;
+    sp<V2_2::IComposerClient> mClient_2_2;
+    sp<IComposerClient> mClient_2_3;
 
     // 64KiB minus a small space for metadata such as read/write pointers
     static constexpr size_t kWriterInitialSize =
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
new file mode 100644
index 0000000..dcc4138
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.cpp
@@ -0,0 +1,185 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "DisplayIdentification"
+
+#include <algorithm>
+#include <cctype>
+#include <numeric>
+#include <optional>
+
+#include <log/log.h>
+
+#include "DisplayIdentification.h"
+
+namespace android {
+namespace {
+
+using byte_view = std::basic_string_view<uint8_t>;
+
+constexpr size_t kEdidHeaderLength = 5;
+
+std::optional<uint8_t> getEdidDescriptorType(const byte_view& view) {
+    if (view.size() < kEdidHeaderLength || view[0] || view[1] || view[2] || view[4]) {
+        return {};
+    }
+
+    return view[3];
+}
+
+std::string_view parseEdidText(const byte_view& view) {
+    std::string_view text(reinterpret_cast<const char*>(view.data()), view.size());
+    text = text.substr(0, text.find('\n'));
+
+    if (!std::all_of(text.begin(), text.end(), ::isprint)) {
+        ALOGW("Invalid EDID: ASCII text is not printable.");
+        return {};
+    }
+
+    return text;
+}
+
+// Big-endian 16-bit value encodes three 5-bit letters where A is 0b00001.
+template <size_t I>
+char getPnpLetter(uint16_t id) {
+    static_assert(I < 3);
+    const char letter = 'A' + (static_cast<uint8_t>(id >> ((2 - I) * 5)) & 0b00011111) - 1;
+    return letter < 'A' || letter > 'Z' ? '\0' : letter;
+}
+
+DisplayId getEdidDisplayId(uint8_t port, uint16_t manufacturerId, uint32_t displayNameHash) {
+    return (static_cast<DisplayId>(manufacturerId) << 40) |
+            (static_cast<DisplayId>(displayNameHash) << 8) | port;
+}
+
+} // namespace
+
+bool isEdid(const DisplayIdentificationData& data) {
+    const uint8_t kMagic[] = {0, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0};
+    return data.size() >= sizeof(kMagic) &&
+            std::equal(std::begin(kMagic), std::end(kMagic), data.begin());
+}
+
+std::optional<Edid> parseEdid(const DisplayIdentificationData& edid) {
+    constexpr size_t kMinLength = 128;
+    if (edid.size() < kMinLength) {
+        ALOGW("Invalid EDID: structure is truncated.");
+        // Attempt parsing even if EDID is malformed.
+    } else {
+        ALOGW_IF(edid[126] != 0, "EDID extensions are currently unsupported.");
+        ALOGW_IF(std::accumulate(edid.begin(), edid.begin() + kMinLength, static_cast<uint8_t>(0)),
+                 "Invalid EDID: structure does not checksum.");
+    }
+
+    constexpr size_t kManufacturerOffset = 8;
+    if (edid.size() < kManufacturerOffset + sizeof(uint16_t)) {
+        ALOGE("Invalid EDID: manufacturer ID is truncated.");
+        return {};
+    }
+
+    // Plug and play ID encoded as big-endian 16-bit value.
+    const uint16_t manufacturerId =
+            (edid[kManufacturerOffset] << 8) | edid[kManufacturerOffset + 1];
+
+    const auto pnpId = getPnpId(manufacturerId);
+    if (!pnpId) {
+        ALOGE("Invalid EDID: manufacturer ID is not a valid PnP ID.");
+        return {};
+    }
+
+    constexpr size_t kDescriptorOffset = 54;
+    if (edid.size() < kDescriptorOffset) {
+        ALOGE("Invalid EDID: descriptors are missing.");
+        return {};
+    }
+
+    byte_view view(edid.data(), edid.size());
+    view.remove_prefix(kDescriptorOffset);
+
+    std::string_view displayName;
+    std::string_view serialNumber;
+    std::string_view asciiText;
+
+    constexpr size_t kDescriptorCount = 4;
+    constexpr size_t kDescriptorLength = 18;
+
+    for (size_t i = 0; i < kDescriptorCount; i++) {
+        if (view.size() < kDescriptorLength) {
+            break;
+        }
+
+        if (const auto type = getEdidDescriptorType(view)) {
+            byte_view descriptor(view.data(), kDescriptorLength);
+            descriptor.remove_prefix(kEdidHeaderLength);
+
+            switch (*type) {
+                case 0xfc:
+                    displayName = parseEdidText(descriptor);
+                    break;
+                case 0xfe:
+                    asciiText = parseEdidText(descriptor);
+                    break;
+                case 0xff:
+                    serialNumber = parseEdidText(descriptor);
+                    break;
+            }
+        }
+
+        view.remove_prefix(kDescriptorLength);
+    }
+
+    if (displayName.empty()) {
+        ALOGW("Invalid EDID: falling back to serial number due to missing display name.");
+        displayName = serialNumber;
+    }
+    if (displayName.empty()) {
+        ALOGW("Invalid EDID: falling back to ASCII text due to missing serial number.");
+        displayName = asciiText;
+    }
+    if (displayName.empty()) {
+        ALOGE("Invalid EDID: display name and fallback descriptors are missing.");
+        return {};
+    }
+
+    return Edid{manufacturerId, *pnpId, displayName};
+}
+
+std::optional<PnpId> getPnpId(uint16_t manufacturerId) {
+    const char a = getPnpLetter<0>(manufacturerId);
+    const char b = getPnpLetter<1>(manufacturerId);
+    const char c = getPnpLetter<2>(manufacturerId);
+    return a && b && c ? std::make_optional(PnpId{a, b, c}) : std::nullopt;
+}
+
+std::optional<DisplayId> generateDisplayId(uint8_t port, const DisplayIdentificationData& data) {
+    if (!isEdid(data)) {
+        ALOGE("Display identification data has unknown format.");
+        return {};
+    }
+
+    const auto edid = parseEdid(data);
+    if (!edid) {
+        return {};
+    }
+
+    // Hash display name instead of using product code or serial number, since the latter have been
+    // observed to change on some displays with multiple inputs.
+    const auto hash = static_cast<uint32_t>(std::hash<std::string_view>()(edid->displayName));
+    return getEdidDisplayId(port, edid->manufacturerId, hash);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/DisplayIdentification.h b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
new file mode 100644
index 0000000..379f2d3
--- /dev/null
+++ b/services/surfaceflinger/DisplayHardware/DisplayIdentification.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 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 <array>
+#include <cstdint>
+#include <optional>
+#include <string_view>
+#include <vector>
+
+namespace android {
+
+using DisplayId = uint64_t;
+using DisplayIdentificationData = std::vector<uint8_t>;
+
+// NUL-terminated plug and play ID.
+using PnpId = std::array<char, 4>;
+
+struct Edid {
+    uint16_t manufacturerId;
+    PnpId pnpId;
+    std::string_view displayName;
+};
+
+bool isEdid(const DisplayIdentificationData&);
+std::optional<Edid> parseEdid(const DisplayIdentificationData&);
+std::optional<PnpId> getPnpId(uint16_t manufacturerId);
+
+std::optional<DisplayId> generateDisplayId(uint8_t port, const DisplayIdentificationData&);
+
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.cpp b/services/surfaceflinger/DisplayHardware/HWC2.cpp
index 1a60c83..ef31908 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWC2.cpp
@@ -124,6 +124,12 @@
     return mComposer->getMaxVirtualDisplayCount();
 }
 
+Error Device::getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
+                                           std::vector<uint8_t>* outData) const {
+    auto intError = mComposer->getDisplayIdentificationData(hwcDisplayId, outPort, outData);
+    return static_cast<Error>(intError);
+}
+
 Error Device::createVirtualDisplay(uint32_t width, uint32_t height,
         PixelFormat* format, Display** outDisplay)
 {
@@ -403,21 +409,17 @@
     return static_cast<Error>(intError);
 }
 
-Error Display::getSupportedPerFrameMetadata(int32_t* outSupportedPerFrameMetadata) const
+int32_t Display::getSupportedPerFrameMetadata() const
 {
-    *outSupportedPerFrameMetadata = 0;
-    std::vector<Hwc2::PerFrameMetadataKey> tmpKeys;
-    auto intError = mComposer.getPerFrameMetadataKeys(mId, &tmpKeys);
-    auto error = static_cast<Error>(intError);
-    if (error != Error::None) {
-        return error;
-    }
+    int32_t supportedPerFrameMetadata = 0;
+
+    std::vector<Hwc2::PerFrameMetadataKey> tmpKeys = mComposer.getPerFrameMetadataKeys(mId);
+    std::set<Hwc2::PerFrameMetadataKey> keys(tmpKeys.begin(), tmpKeys.end());
 
     // Check whether a specific metadata type is supported. A metadata type is considered
     // supported if and only if all required fields are supported.
 
     // SMPTE2086
-    std::set<Hwc2::PerFrameMetadataKey> keys(tmpKeys.begin(), tmpKeys.end());
     if (hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X) &&
         hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y) &&
         hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X) &&
@@ -428,15 +430,15 @@
         hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::WHITE_POINT_Y) &&
         hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::MAX_LUMINANCE) &&
         hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::MIN_LUMINANCE)) {
-        *outSupportedPerFrameMetadata |= HdrMetadata::Type::SMPTE2086;
+        supportedPerFrameMetadata |= HdrMetadata::Type::SMPTE2086;
     }
     // CTA861_3
     if (hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL) &&
         hasMetadataKey(keys, Hwc2::PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL)) {
-        *outSupportedPerFrameMetadata |= HdrMetadata::Type::CTA861_3;
+        supportedPerFrameMetadata |= HdrMetadata::Type::CTA861_3;
     }
 
-    return Error::None;
+    return supportedPerFrameMetadata;
 }
 
 Error Display::getRenderIntents(ColorMode colorMode,
diff --git a/services/surfaceflinger/DisplayHardware/HWC2.h b/services/surfaceflinger/DisplayHardware/HWC2.h
index e423167..900b3d7 100644
--- a/services/surfaceflinger/DisplayHardware/HWC2.h
+++ b/services/surfaceflinger/DisplayHardware/HWC2.h
@@ -95,6 +95,9 @@
     };
 
     uint32_t getMaxVirtualDisplayCount() const;
+    Error getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
+                                       std::vector<uint8_t>* outData) const;
+
     Error createVirtualDisplay(uint32_t width, uint32_t height,
             android::ui::PixelFormat* format, Display** outDisplay);
     void destroyDisplay(hwc2_display_t displayId);
@@ -215,10 +218,8 @@
             std::unordered_map<Layer*, Composition>* outTypes);
     [[clang::warn_unused_result]] Error getColorModes(
             std::vector<android::ui::ColorMode>* outModes) const;
-    // outSupportedPerFrameMetadata is an opaque bitmask to the callers
-    // but contains HdrMetadata::Type::*.
-    [[clang::warn_unused_result]] Error getSupportedPerFrameMetadata(
-            int32_t* outSupportedPerFrameMetadata) const;
+    // Returns a bitmask which contains HdrMetadata::Type::*.
+    [[clang::warn_unused_result]] int32_t getSupportedPerFrameMetadata() const;
     [[clang::warn_unused_result]] Error getRenderIntents(
             android::ui::ColorMode colorMode,
             std::vector<android::ui::RenderIntent>* outRenderIntents) const;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index f5f7a82..bf8905a 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -54,6 +54,9 @@
 #include "../Layer.h"           // needed only for debugging
 #include "../SurfaceFlinger.h"
 
+#define LOG_HWC_DISPLAY_ERROR(hwcDisplayId, msg) \
+    ALOGE("%s failed for HWC display %" PRIu64 ": %s", __FUNCTION__, hwcDisplayId, msg)
+
 #define LOG_DISPLAY_ERROR(displayId, msg) \
     ALOGE("%s failed for display %d: %s", __FUNCTION__, displayId, msg)
 
@@ -96,6 +99,18 @@
     mHwcDevice->registerCallback(callback, sequenceId);
 }
 
+bool HWComposer::getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
+                                              DisplayIdentificationData* outData) const {
+    const auto error = mHwcDevice->getDisplayIdentificationData(hwcDisplayId, outPort, outData);
+    if (error != HWC2::Error::None) {
+        if (error != HWC2::Error::Unsupported) {
+            LOG_HWC_DISPLAY_ERROR(hwcDisplayId, to_string(error).c_str());
+        }
+        return false;
+    }
+    return true;
+}
+
 bool HWComposer::hasCapability(HWC2::Capability capability) const
 {
     return mHwcDevice->getCapabilities().count(capability) > 0;
@@ -131,53 +146,53 @@
     }
 }
 
-void HWComposer::onHotplug(hwc2_display_t displayId, int32_t displayType,
-                           HWC2::Connection connection) {
+std::optional<DisplayId> HWComposer::onHotplug(hwc2_display_t hwcDisplayId, int32_t displayType,
+                                               HWC2::Connection connection) {
     if (displayType >= HWC_NUM_PHYSICAL_DISPLAY_TYPES) {
         ALOGE("Invalid display type of %d", displayType);
-        return;
+        return {};
     }
 
-    ALOGV("hotplug: %" PRIu64 ", %s %s", displayId,
-            displayType == DisplayDevice::DISPLAY_PRIMARY ? "primary" : "external",
-            to_string(connection).c_str());
-    mHwcDevice->onHotplug(displayId, connection);
+    ALOGV("hotplug: %" PRIu64 ", %s %s", hwcDisplayId,
+          displayType == DisplayDevice::DISPLAY_PRIMARY ? "primary" : "external",
+          to_string(connection).c_str());
+    mHwcDevice->onHotplug(hwcDisplayId, connection);
+
+    std::optional<DisplayId> displayId;
+
+    uint8_t port;
+    DisplayIdentificationData data;
+    if (getDisplayIdentificationData(hwcDisplayId, &port, &data)) {
+        displayId = generateDisplayId(port, data);
+        ALOGE_IF(!displayId, "Failed to generate stable ID for display %" PRIu64, hwcDisplayId);
+    }
+
     // Disconnect is handled through HWComposer::disconnectDisplay via
     // SurfaceFlinger's onHotplugReceived callback handling
     if (connection == HWC2::Connection::Connected) {
-        mDisplayData[displayType].hwcDisplay = mHwcDevice->getDisplayById(displayId);
-        mHwcDisplaySlots[displayId] = displayType;
+        mDisplayData[displayType].hwcDisplay = mHwcDevice->getDisplayById(hwcDisplayId);
+        mHwcDisplaySlots[hwcDisplayId] = displayType;
     }
+
+    return displayId;
 }
 
-bool HWComposer::onVsync(hwc2_display_t displayId, int64_t timestamp,
-                         int32_t* outDisplay) {
-    auto display = mHwcDevice->getDisplayById(displayId);
-    if (!display) {
-        ALOGE("onVsync Failed to find display %" PRIu64, displayId);
-        return false;
-    }
-    auto displayType = HWC2::DisplayType::Invalid;
-    auto error = display->getType(&displayType);
-    if (error != HWC2::Error::None) {
-        ALOGE("onVsync: Failed to determine type of display %" PRIu64,
-                display->getId());
+bool HWComposer::onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplayId) {
+    const auto it = mHwcDisplaySlots.find(hwcDisplayId);
+    if (it == mHwcDisplaySlots.end()) {
+        LOG_HWC_DISPLAY_ERROR(hwcDisplayId, "Invalid display");
         return false;
     }
 
-    if (displayType == HWC2::DisplayType::Virtual) {
-        ALOGE("Virtual display %" PRIu64 " passed to vsync callback",
-                display->getId());
+    const int32_t displayId = it->second;
+    RETURN_IF_INVALID_DISPLAY(displayId, false);
+
+    const auto& displayData = mDisplayData[displayId];
+    if (displayData.isVirtual) {
+        LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
         return false;
     }
 
-    if (mHwcDisplaySlots.count(display->getId()) == 0) {
-        ALOGE("Unknown physical display %" PRIu64 " passed to vsync callback",
-                display->getId());
-        return false;
-    }
-
-    int32_t disp = mHwcDisplaySlots[display->getId()];
     {
         Mutex::Autolock _l(mLock);
 
@@ -185,22 +200,22 @@
         // with the same timestamp when turning the display off and on. This
         // is a bug in the HWC implementation, but filter the extra events
         // out here so they don't cause havoc downstream.
-        if (timestamp == mLastHwVSync[disp]) {
+        if (timestamp == mLastHwVSync[displayId]) {
             ALOGW("Ignoring duplicate VSYNC event from HWC (t=%" PRId64 ")",
                     timestamp);
             return false;
         }
 
-        mLastHwVSync[disp] = timestamp;
+        mLastHwVSync[displayId] = timestamp;
     }
 
-    if (outDisplay) {
-        *outDisplay = disp;
+    if (outDisplayId) {
+        *outDisplayId = displayId;
     }
 
     char tag[16];
-    snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", disp);
-    ATRACE_INT(tag, ++mVSyncCounts[disp] & 1);
+    snprintf(tag, sizeof(tag), "HW_VSYNC_%1u", displayId);
+    ATRACE_INT(tag, ++mVSyncCounts[displayId] & 1);
 
     return true;
 }
@@ -208,16 +223,15 @@
 status_t HWComposer::allocateVirtualDisplay(uint32_t width, uint32_t height,
         ui::PixelFormat* format, int32_t *outId) {
     if (mRemainingHwcVirtualDisplays == 0) {
-        ALOGE("allocateVirtualDisplay: No remaining virtual displays");
+        ALOGE("%s: No remaining virtual displays", __FUNCTION__);
         return NO_MEMORY;
     }
 
     if (SurfaceFlinger::maxVirtualDisplaySize != 0 &&
         (width > SurfaceFlinger::maxVirtualDisplaySize ||
          height > SurfaceFlinger::maxVirtualDisplaySize)) {
-        ALOGE("createVirtualDisplay: Can't create a virtual display with"
-                      " a dimension > %" PRIu64 " (tried %u x %u)",
-              SurfaceFlinger::maxVirtualDisplaySize, width, height);
+        ALOGE("%s: Display size %ux%u exceeds maximum dimension of %" PRIu64, __FUNCTION__, width,
+              height, SurfaceFlinger::maxVirtualDisplaySize);
         return INVALID_OPERATION;
     }
 
@@ -225,7 +239,7 @@
     auto error = mHwcDevice->createVirtualDisplay(width, height, format,
             &display);
     if (error != HWC2::Error::None) {
-        ALOGE("allocateVirtualDisplay: Failed to create HWC virtual display");
+        ALOGE("%s: Failed to create HWC virtual display", __FUNCTION__);
         return NO_MEMORY;
     }
 
@@ -238,11 +252,13 @@
         displaySlot = mDisplayData.size();
         mDisplayData.resize(displaySlot + 1);
     } else {
-        ALOGE("allocateVirtualDisplay: Unable to allocate a display slot");
+        ALOGE("%s: Unable to allocate a display slot", __FUNCTION__);
         return NO_MEMORY;
     }
 
-    mDisplayData[displaySlot].hwcDisplay = display;
+    auto& displayData = mDisplayData[displaySlot];
+    displayData.hwcDisplay = display;
+    displayData.isVirtual = true;
 
     --mRemainingHwcVirtualDisplays;
     *outId = static_cast<int32_t>(displaySlot);
@@ -319,21 +335,19 @@
 }
 
 int HWComposer::getActiveConfigIndex(int32_t displayId) const {
-    if (!isValidDisplay(displayId)) {
-        ALOGV("getActiveConfigIndex: Attempted to access invalid display %d", displayId);
-        return -1;
-    }
+    RETURN_IF_INVALID_DISPLAY(displayId, -1);
+
     int index;
     auto error = mDisplayData[displayId].hwcDisplay->getActiveConfigIndex(&index);
     if (error == HWC2::Error::BadConfig) {
-        ALOGE("getActiveConfigIndex: No config active, returning -1");
+        LOG_DISPLAY_ERROR(displayId, "No active config");
         return -1;
-    } else if (error != HWC2::Error::None) {
-        ALOGE("getActiveConfigIndex failed for display %d: %s (%d)", displayId,
-              to_string(error).c_str(), static_cast<int32_t>(error));
-        return -1;
-    } else if (index < 0) {
-        ALOGE("getActiveConfigIndex returned an unknown config for display %d", displayId);
+    }
+
+    RETURN_IF_HWC_ERROR(error, displayId, -1);
+
+    if (index < 0) {
+        LOG_DISPLAY_ERROR(displayId, "Unknown config");
         return -1;
     }
 
@@ -365,19 +379,19 @@
 
 
 void HWComposer::setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled) {
-    if (displayId < 0 || displayId >= HWC_DISPLAY_VIRTUAL) {
-        ALOGD("setVsyncEnabled: Ignoring for virtual display %d", displayId);
+    RETURN_IF_INVALID_DISPLAY(displayId);
+    auto& displayData = mDisplayData[displayId];
+
+    if (displayData.isVirtual) {
+        LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
         return;
     }
 
-    RETURN_IF_INVALID_DISPLAY(displayId);
-
     // NOTE: we use our own internal lock here because we have to call
     // into the HWC with the lock held, and we want to make sure
     // that even if HWC blocks (which it shouldn't), it won't
     // affect other threads.
     Mutex::Autolock _l(mVsyncLock);
-    auto& displayData = mDisplayData[displayId];
     if (enabled != displayData.vsyncEnabled) {
         ATRACE_CALL();
         auto error = displayData.hwcDisplay->setVsyncEnabled(enabled);
@@ -403,11 +417,11 @@
     return NO_ERROR;
 }
 
-status_t HWComposer::prepare(DisplayDevice& displayDevice) {
+status_t HWComposer::prepare(DisplayDevice& display) {
     ATRACE_CALL();
 
     Mutex::Autolock _l(mDisplayLock);
-    auto displayId = displayDevice.getHwcDisplayId();
+    const auto displayId = display.getId();
     if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
         ALOGV("Skipping HWComposer prepare for non-HWC display");
         return NO_ERROR;
@@ -474,7 +488,7 @@
 
     displayData.hasClientComposition = false;
     displayData.hasDeviceComposition = false;
-    for (auto& layer : displayDevice.getVisibleLayersSortedByZ()) {
+    for (auto& layer : display.getVisibleLayersSortedByZ()) {
         auto hwcLayer = layer->getHwcLayer(displayId);
 
         if (changedTypes.count(hwcLayer) != 0) {
@@ -601,7 +615,8 @@
     ALOGV("setPowerMode(%d, %d)", displayId, intMode);
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
 
-    if (displayId >= VIRTUAL_DISPLAY_ID_BASE) {
+    const auto& displayData = mDisplayData[displayId];
+    if (displayData.isVirtual) {
         LOG_DISPLAY_ERROR(displayId, "Invalid operation on virtual display");
         return INVALID_OPERATION;
     }
@@ -611,7 +626,7 @@
         setVsyncEnabled(displayId, HWC2::Vsync::Disable);
     }
 
-    auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
+    auto& hwcDisplay = displayData.hwcDisplay;
     switch (mode) {
         case HWC2::PowerMode::Off:
         case HWC2::PowerMode::On:
@@ -680,43 +695,35 @@
     return NO_ERROR;
 }
 
-void HWComposer::disconnectDisplay(int displayId) {
-    LOG_ALWAYS_FATAL_IF(displayId < 0);
+void HWComposer::disconnectDisplay(int32_t displayId) {
+    RETURN_IF_INVALID_DISPLAY(displayId);
     auto& displayData = mDisplayData[displayId];
 
-    auto displayType = HWC2::DisplayType::Invalid;
-    auto error = displayData.hwcDisplay->getType(&displayType);
-    RETURN_IF_HWC_ERROR_FOR("getType", error, displayId);
-
     // If this was a virtual display, add its slot back for reuse by future
     // virtual displays
-    if (displayType == HWC2::DisplayType::Virtual) {
+    if (displayData.isVirtual) {
         mFreeDisplaySlots.insert(displayId);
         ++mRemainingHwcVirtualDisplays;
     }
 
-    auto hwcId = displayData.hwcDisplay->getId();
-    mHwcDisplaySlots.erase(hwcId);
-    displayData.reset();
+    const auto hwcDisplayId = displayData.hwcDisplay->getId();
+    mHwcDisplaySlots.erase(hwcDisplayId);
+    displayData = DisplayData();
 
-    mHwcDevice->destroyDisplay(hwcId);
+    mHwcDevice->destroyDisplay(hwcDisplayId);
 }
 
 status_t HWComposer::setOutputBuffer(int32_t displayId,
         const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buffer) {
     RETURN_IF_INVALID_DISPLAY(displayId, BAD_INDEX);
+    const auto& displayData = mDisplayData[displayId];
 
-    auto& hwcDisplay = mDisplayData[displayId].hwcDisplay;
-    auto displayType = HWC2::DisplayType::Invalid;
-    auto error = hwcDisplay->getType(&displayType);
-    RETURN_IF_HWC_ERROR_FOR("getType", error, displayId, NAME_NOT_FOUND);
-
-    if (displayType != HWC2::DisplayType::Virtual) {
+    if (!displayData.isVirtual) {
         LOG_DISPLAY_ERROR(displayId, "Invalid operation on physical display");
         return INVALID_OPERATION;
     }
 
-    error = hwcDisplay->setOutputBuffer(buffer, acquireFence);
+    auto error = displayData.hwcDisplay->setOutputBuffer(buffer, acquireFence);
     RETURN_IF_HWC_ERROR(error, displayId, UNKNOWN_ERROR);
     return NO_ERROR;
 }
@@ -738,12 +745,7 @@
 
 int32_t HWComposer::getSupportedPerFrameMetadata(int32_t displayId) const {
     RETURN_IF_INVALID_DISPLAY(displayId, 0);
-
-    int32_t supportedMetadata;
-    auto error = mDisplayData[displayId].hwcDisplay->getSupportedPerFrameMetadata(
-            &supportedMetadata);
-    RETURN_IF_HWC_ERROR(error, displayId, 0);
-    return supportedMetadata;
+    return mDisplayData[displayId].hwcDisplay->getSupportedPerFrameMetadata();
 }
 
 std::vector<ui::RenderIntent> HWComposer::getRenderIntents(int32_t displayId,
@@ -805,26 +807,4 @@
     return mDisplayData[displayId].hwcDisplay->getId();
 }
 
-// ---------------------------------------------------------------------------
-
-HWComposer::DisplayData::DisplayData()
-  : hasClientComposition(false),
-    hasDeviceComposition(false),
-    hwcDisplay(nullptr),
-    lastPresentFence(Fence::NO_FENCE),
-    outbufHandle(nullptr),
-    outbufAcquireFence(Fence::NO_FENCE),
-    vsyncEnabled(HWC2::Vsync::Disable) {
-    ALOGV("Created new DisplayData");
-}
-
-HWComposer::DisplayData::~DisplayData() {
-}
-
-void HWComposer::DisplayData::reset() {
-    ALOGV("DisplayData reset");
-    *this = DisplayData();
-}
-
-// ---------------------------------------------------------------------------
-}; // namespace android
+} // namespace android
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index f968948..3c5efea 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -37,6 +37,8 @@
 #include <set>
 #include <vector>
 
+#include "DisplayIdentification.h"
+
 extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
                            const struct timespec *request,
                            struct timespec *remain);
@@ -74,6 +76,9 @@
     void registerCallback(HWC2::ComposerCallback* callback,
                           int32_t sequenceId);
 
+    bool getDisplayIdentificationData(hwc2_display_t hwcDisplayId, uint8_t* outPort,
+                                      DisplayIdentificationData* outData) const;
+
     bool hasCapability(HWC2::Capability capability) const;
 
     // Attempts to allocate a virtual display. If the virtual display is created
@@ -87,7 +92,7 @@
     void destroyLayer(int32_t displayId, HWC2::Layer* layer);
 
     // Asks the HAL what it can do
-    status_t prepare(DisplayDevice& displayDevice);
+    status_t prepare(DisplayDevice& display);
 
     status_t setClientTarget(int32_t displayId, uint32_t slot,
             const sp<Fence>& acquireFence,
@@ -147,9 +152,9 @@
 
     // Returns true if successful, false otherwise. The
     // DisplayDevice::DisplayType of the display is returned as an output param.
-    bool onVsync(hwc2_display_t displayId, int64_t timestamp,
-                 int32_t* outDisplay);
-    void onHotplug(hwc2_display_t displayId, int32_t displayType, HWC2::Connection connection);
+    bool onVsync(hwc2_display_t hwcDisplayId, int64_t timestamp, int32_t* outDisplay);
+    std::optional<DisplayId> onHotplug(hwc2_display_t hwcDisplayId, int32_t displayType,
+                                       HWC2::Connection connection);
 
     void setVsyncEnabled(int32_t displayId, HWC2::Vsync enabled);
 
@@ -183,31 +188,26 @@
     // For unit tests
     friend TestableSurfaceFlinger;
 
-    static const int32_t VIRTUAL_DISPLAY_ID_BASE = 2;
-
     bool isValidDisplay(int32_t displayId) const;
     static void validateChange(HWC2::Composition from, HWC2::Composition to);
 
     struct cb_context;
 
     struct DisplayData {
-        DisplayData();
-        ~DisplayData();
-        void reset();
-
-        bool hasClientComposition;
-        bool hasDeviceComposition;
-        HWC2::Display* hwcDisplay;
+        bool isVirtual = false;
+        bool hasClientComposition = false;
+        bool hasDeviceComposition = false;
+        HWC2::Display* hwcDisplay = nullptr;
         HWC2::DisplayRequest displayRequests;
-        sp<Fence> lastPresentFence;  // signals when the last set op retires
+        sp<Fence> lastPresentFence = Fence::NO_FENCE; // signals when the last set op retires
         std::unordered_map<HWC2::Layer*, sp<Fence>> releaseFences;
-        buffer_handle_t outbufHandle;
-        sp<Fence> outbufAcquireFence;
+        buffer_handle_t outbufHandle = nullptr;
+        sp<Fence> outbufAcquireFence = Fence::NO_FENCE;
         mutable std::unordered_map<int32_t,
                 std::shared_ptr<const HWC2::Display::Config>> configMap;
 
         // protected by mVsyncLock
-        HWC2::Vsync vsyncEnabled;
+        HWC2::Vsync vsyncEnabled = HWC2::Vsync::Disable;
 
         bool validateWasSkipped;
         HWC2::Error presentError;
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h b/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
deleted file mode 100644
index fe7944f..0000000
--- a/services/surfaceflinger/DisplayHardware/HWComposer_hwc1.h
+++ /dev/null
@@ -1,400 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef ANDROID_SF_HWCOMPOSER_HWC1_H
-#define ANDROID_SF_HWCOMPOSER_HWC1_H
-
-#include <stdint.h>
-#include <sys/types.h>
-
-#include <hardware/hwcomposer_defs.h>
-
-#include <system/graphics.h>
-
-#include <ui/Fence.h>
-
-#include <utils/BitSet.h>
-#include <utils/Condition.h>
-#include <utils/Mutex.h>
-#include <utils/StrongPointer.h>
-#include <utils/Thread.h>
-#include <utils/Timers.h>
-#include <utils/Vector.h>
-
-extern "C" int clock_nanosleep(clockid_t clock_id, int flags,
-                           const struct timespec *request,
-                           struct timespec *remain);
-
-struct hwc_composer_device_1;
-struct hwc_display_contents_1;
-struct hwc_layer_1;
-struct hwc_procs;
-struct framebuffer_device_t;
-
-namespace android {
-// ---------------------------------------------------------------------------
-
-class Fence;
-class FloatRect;
-class GraphicBuffer;
-class NativeHandle;
-class Region;
-class String8;
-class SurfaceFlinger;
-
-class HWComposer
-{
-public:
-    class EventHandler {
-        friend class HWComposer;
-        virtual void onVSyncReceived(
-            HWComposer* composer, int32_t disp, nsecs_t timestamp) = 0;
-        virtual void onHotplugReceived(HWComposer* composer, int disp, bool connected) = 0;
-        virtual void onInvalidateReceived(HWComposer* composer) = 0;
-    protected:
-        virtual ~EventHandler() {}
-    };
-
-    enum {
-        NUM_BUILTIN_DISPLAYS = HWC_NUM_PHYSICAL_DISPLAY_TYPES,
-        MAX_HWC_DISPLAYS = HWC_NUM_DISPLAY_TYPES,
-        VIRTUAL_DISPLAY_ID_BASE = HWC_DISPLAY_VIRTUAL,
-    };
-
-    HWComposer(
-            const sp<SurfaceFlinger>& flinger,
-            EventHandler& handler);
-
-    ~HWComposer();
-
-    status_t initCheck() const;
-
-    // Returns a display ID starting at VIRTUAL_DISPLAY_ID_BASE, this ID is to
-    // be used with createWorkList (and all other methods requiring an ID
-    // below).
-    // IDs below NUM_BUILTIN_DISPLAYS are pre-defined and therefore are
-    // always valid.
-    // Returns -1 if an ID cannot be allocated
-    int32_t allocateDisplayId();
-
-    // Recycles the given virtual display ID and frees the associated worklist.
-    // IDs below NUM_BUILTIN_DISPLAYS are not recycled.
-    status_t freeDisplayId(int32_t id);
-
-
-    // Asks the HAL what it can do
-    status_t prepare();
-
-    // commits the list
-    status_t commit();
-
-    // set power mode
-    status_t setPowerMode(int disp, int mode);
-
-    // set active config
-    status_t setActiveConfig(int disp, int mode);
-
-    // reset state when an external, non-virtual display is disconnected
-    void disconnectDisplay(int disp);
-
-    // create a work list for numLayers layer. sets HWC_GEOMETRY_CHANGED.
-    status_t createWorkList(int32_t id, size_t numLayers);
-
-    bool supportsFramebufferTarget() const;
-
-    // does this display have layers handled by HWC
-    bool hasHwcComposition(int32_t id) const;
-
-    // does this display have layers handled by GLES
-    bool hasGlesComposition(int32_t id) const;
-
-    // get the releaseFence file descriptor for a display's framebuffer layer.
-    // the release fence is only valid after commit()
-    sp<Fence> getAndResetReleaseFence(int32_t id);
-
-    // needed forward declarations
-    class LayerListIterator;
-
-    // return the visual id to be used to find a suitable EGLConfig for
-    // *ALL* displays.
-    int getVisualID() const;
-
-    // Forwarding to FB HAL for pre-HWC-1.1 code (see FramebufferSurface).
-    int fbPost(int32_t id, const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
-    int fbCompositionComplete();
-    void fbDump(String8& result);
-
-    // Set the output buffer and acquire fence for a virtual display.
-    // Returns INVALID_OPERATION if id is not a virtual display.
-    status_t setOutputBuffer(int32_t id, const sp<Fence>& acquireFence,
-            const sp<GraphicBuffer>& buf);
-
-    // Get the retire fence for the last committed frame. This fence will
-    // signal when the h/w composer is completely finished with the frame.
-    // For physical displays, it is no longer being displayed. For virtual
-    // displays, writes to the output buffer are complete.
-    sp<Fence> getLastRetireFence(int32_t id) const;
-
-    status_t setCursorPositionAsync(int32_t id, const Rect &pos);
-
-    /*
-     * Interface to hardware composer's layers functionality.
-     * This abstracts the HAL interface to layers which can evolve in
-     * incompatible ways from one release to another.
-     * The idea is that we could extend this interface as we add
-     * features to h/w composer.
-     */
-    class HWCLayerInterface {
-    protected:
-        virtual ~HWCLayerInterface() { }
-    public:
-        virtual int32_t getCompositionType() const = 0;
-        virtual uint32_t getHints() const = 0;
-        virtual sp<Fence> getAndResetReleaseFence() = 0;
-        virtual void setDefaultState() = 0;
-        virtual void setSkip(bool skip) = 0;
-        virtual void setIsCursorLayerHint(bool isCursor = true) = 0;
-        virtual void setBlending(uint32_t blending) = 0;
-        virtual void setTransform(uint32_t transform) = 0;
-        virtual void setFrame(const Rect& frame) = 0;
-        virtual void setCrop(const FloatRect& crop) = 0;
-        virtual void setVisibleRegionScreen(const Region& reg) = 0;
-        virtual void setSurfaceDamage(const Region& reg) = 0;
-        virtual void setSidebandStream(const sp<NativeHandle>& stream) = 0;
-        virtual void setBuffer(const sp<GraphicBuffer>& buffer) = 0;
-        virtual void setAcquireFenceFd(int fenceFd) = 0;
-        virtual void setPlaneAlpha(uint8_t alpha) = 0;
-        virtual void onDisplayed() = 0;
-    };
-
-    /*
-     * Interface used to implement an iterator to a list
-     * of HWCLayer.
-     */
-    class HWCLayer : public HWCLayerInterface {
-        friend class LayerListIterator;
-        // select the layer at the given index
-        virtual status_t setLayer(size_t index) = 0;
-        virtual HWCLayer* dup() = 0;
-        static HWCLayer* copy(HWCLayer *rhs) {
-            return rhs ? rhs->dup() : nullptr;
-        }
-    protected:
-        virtual ~HWCLayer() { }
-    };
-
-    /*
-     * Iterator through a HWCLayer list.
-     * This behaves more or less like a forward iterator.
-     */
-    class LayerListIterator {
-        friend class HWComposer;
-        HWCLayer* const mLayerList;
-        size_t mIndex;
-
-        LayerListIterator() : mLayerList(nullptr), mIndex(0) { }
-
-        LayerListIterator(HWCLayer* layer, size_t index)
-            : mLayerList(layer), mIndex(index) { }
-
-        // we don't allow assignment, because we don't need it for now
-        LayerListIterator& operator = (const LayerListIterator& rhs);
-
-    public:
-        // copy operators
-        LayerListIterator(const LayerListIterator& rhs)
-            : mLayerList(HWCLayer::copy(rhs.mLayerList)), mIndex(rhs.mIndex) {
-        }
-
-        ~LayerListIterator() { delete mLayerList; }
-
-        // pre-increment
-        LayerListIterator& operator++() {
-            mLayerList->setLayer(++mIndex);
-            return *this;
-        }
-
-        // dereference
-        HWCLayerInterface& operator * () { return *mLayerList; }
-        HWCLayerInterface* operator -> () { return mLayerList; }
-
-        // comparison
-        bool operator == (const LayerListIterator& rhs) const {
-            return mIndex == rhs.mIndex;
-        }
-        bool operator != (const LayerListIterator& rhs) const {
-            return !operator==(rhs);
-        }
-    };
-
-    // Returns an iterator to the beginning of the layer list
-    LayerListIterator begin(int32_t id);
-
-    // Returns an iterator to the end of the layer list
-    LayerListIterator end(int32_t id);
-
-
-    // Events handling ---------------------------------------------------------
-
-    enum {
-        EVENT_VSYNC = HWC_EVENT_VSYNC
-    };
-
-    void eventControl(int disp, int event, int enabled);
-
-    struct DisplayConfig {
-        uint32_t width;
-        uint32_t height;
-        float xdpi;
-        float ydpi;
-        nsecs_t refresh;
-        android_color_mode_t colorMode;
-        bool operator==(const DisplayConfig& rhs) const {
-            return width == rhs.width &&
-                    height == rhs.height &&
-                    xdpi == rhs.xdpi &&
-                    ydpi == rhs.ydpi &&
-                    refresh == rhs.refresh &&
-                    colorMode == rhs.colorMode;
-        }
-    };
-
-    // Query display parameters.  Pass in a display index (e.g.
-    // HWC_DISPLAY_PRIMARY).
-    nsecs_t getRefreshTimestamp(int disp) const;
-    sp<Fence> getDisplayFence(int disp) const;
-    uint32_t getFormat(int disp) const;
-    bool isConnected(int disp) const;
-
-    // These return the values for the current config of a given display index.
-    // To get the values for all configs, use getConfigs below.
-    uint32_t getWidth(int disp) const;
-    uint32_t getHeight(int disp) const;
-    float getDpiX(int disp) const;
-    float getDpiY(int disp) const;
-    nsecs_t getRefreshPeriod(int disp) const;
-    android_color_mode_t getColorMode(int disp) const;
-
-    const Vector<DisplayConfig>& getConfigs(int disp) const;
-    size_t getCurrentConfig(int disp) const;
-
-    status_t setVirtualDisplayProperties(int32_t id, uint32_t w, uint32_t h,
-            uint32_t format);
-
-    // this class is only used to fake the VSync event on systems that don't
-    // have it.
-    class VSyncThread : public Thread {
-        HWComposer& mHwc;
-        mutable Mutex mLock;
-        Condition mCondition;
-        bool mEnabled;
-        mutable nsecs_t mNextFakeVSync;
-        nsecs_t mRefreshPeriod;
-        virtual void onFirstRef();
-        virtual bool threadLoop();
-    public:
-        VSyncThread(HWComposer& hwc);
-        void setEnabled(bool enabled);
-    };
-
-    friend class VSyncThread;
-
-    // for debugging ----------------------------------------------------------
-    void dump(String8& out) const;
-
-private:
-    void loadHwcModule();
-    int loadFbHalModule();
-
-    LayerListIterator getLayerIterator(int32_t id, size_t index);
-
-    struct cb_context;
-
-    static void hook_invalidate(const struct hwc_procs* procs);
-    static void hook_vsync(const struct hwc_procs* procs, int disp,
-            int64_t timestamp);
-    static void hook_hotplug(const struct hwc_procs* procs, int disp,
-            int connected);
-
-    inline void invalidate();
-    inline void vsync(int disp, int64_t timestamp);
-    inline void hotplug(int disp, int connected);
-
-    status_t queryDisplayProperties(int disp);
-
-    status_t setFramebufferTarget(int32_t id,
-            const sp<Fence>& acquireFence, const sp<GraphicBuffer>& buf);
-
-    struct DisplayData {
-        DisplayData();
-        ~DisplayData();
-        Vector<DisplayConfig> configs;
-        size_t currentConfig;
-        uint32_t format;    // pixel format from FB hal, for pre-hwc-1.1
-        bool connected;
-        bool hasFbComp;
-        bool hasOvComp;
-        size_t capacity;
-        hwc_display_contents_1* list;
-        hwc_layer_1* framebufferTarget;
-        buffer_handle_t fbTargetHandle;
-        sp<Fence> lastRetireFence;  // signals when the last set op retires
-        sp<Fence> lastDisplayFence; // signals when the last set op takes
-                                    // effect on screen
-        buffer_handle_t outbufHandle;
-        sp<Fence> outbufAcquireFence;
-
-        // protected by mEventControlLock
-        int32_t events;
-
-        // We need to hold "copies" of these for memory management purposes. The
-        // actual hwc_layer_1_t holds pointers to the memory within. Vector<>
-        // internally doesn't copy the memory unless one of the copies is
-        // modified.
-        Vector<Region> visibleRegions;
-        Vector<Region> surfaceDamageRegions;
-    };
-
-    sp<SurfaceFlinger>              mFlinger;
-    framebuffer_device_t*           mFbDev;
-    struct hwc_composer_device_1*   mHwc;
-    // invariant: mLists[0] != nullptr iff mHwc != nullptr
-    // mLists[i>0] can be nullptr. that display is to be ignored
-    struct hwc_display_contents_1*  mLists[MAX_HWC_DISPLAYS];
-    DisplayData                     mDisplayData[MAX_HWC_DISPLAYS];
-    // protect mDisplayData from races between prepare and dump
-    mutable Mutex mDisplayLock;
-    size_t                          mNumDisplays;
-
-    cb_context*                     mCBContext;
-    EventHandler&                   mEventHandler;
-    size_t                          mVSyncCounts[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
-    sp<VSyncThread>                 mVSyncThread;
-    bool                            mDebugForceFakeVSync;
-    BitSet32                        mAllocatedDisplayIDs;
-
-    // protected by mLock
-    mutable Mutex mLock;
-    mutable nsecs_t mLastHwVSync[HWC_NUM_PHYSICAL_DISPLAY_TYPES];
-
-    // thread-safe
-    mutable Mutex mEventControlLock;
-};
-
-// ---------------------------------------------------------------------------
-}; // namespace android
-
-#endif // ANDROID_SF_HWCOMPOSER_H
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 9a2817d..c111a27 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -32,11 +32,11 @@
 // ---------------------------------------------------------------------------
 
 #define VDS_LOGE(msg, ...) ALOGE("[%s] " msg, \
-        mDisplayName.string(), ##__VA_ARGS__)
+        mDisplayName.c_str(), ##__VA_ARGS__)
 #define VDS_LOGW_IF(cond, msg, ...) ALOGW_IF(cond, "[%s] " msg, \
-        mDisplayName.string(), ##__VA_ARGS__)
+        mDisplayName.c_str(), ##__VA_ARGS__)
 #define VDS_LOGV(msg, ...) ALOGV("[%s] " msg, \
-        mDisplayName.string(), ##__VA_ARGS__)
+        mDisplayName.c_str(), ##__VA_ARGS__)
 
 static const char* dbgCompositionTypeStr(DisplaySurface::CompositionType type) {
     switch (type) {
@@ -52,7 +52,7 @@
         const sp<IGraphicBufferProducer>& sink,
         const sp<IGraphicBufferProducer>& bqProducer,
         const sp<IGraphicBufferConsumer>& bqConsumer,
-        const String8& name)
+        const std::string& name)
 :   ConsumerBase(bqConsumer),
     mHwc(hwc),
     mDisplayId(dispId),
@@ -102,7 +102,7 @@
     }
     mOutputFormat = mDefaultOutputFormat;
 
-    ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.string());
+    ConsumerBase::mName = String8::format("VDS: %s", mDisplayName.c_str());
     mConsumer->setConsumerName(ConsumerBase::mName);
     mConsumer->setConsumerUsageBits(GRALLOC_USAGE_HW_COMPOSER);
     mConsumer->setDefaultBufferSize(sinkWidth, sinkHeight);
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 5c8acea..4bd4d0f 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -17,6 +17,8 @@
 #ifndef ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
 #define ANDROID_SF_VIRTUAL_DISPLAY_SURFACE_H
 
+#include <string>
+
 #include "DisplaySurface.h"
 #include "HWComposerBufferCache.h"
 
@@ -77,7 +79,7 @@
             const sp<IGraphicBufferProducer>& sink,
             const sp<IGraphicBufferProducer>& bqProducer,
             const sp<IGraphicBufferConsumer>& bqConsumer,
-            const String8& name);
+            const std::string& name);
 
     //
     // DisplaySurface interface
@@ -153,7 +155,7 @@
     //
     HWComposer& mHwc;
     const int32_t mDisplayId;
-    const String8 mDisplayName;
+    const std::string mDisplayName;
     sp<IGraphicBufferProducer> mSource[2]; // indexed by SOURCE_*
     uint32_t mDefaultOutputFormat;
 
diff --git a/services/surfaceflinger/EventThread.cpp b/services/surfaceflinger/EventThread.cpp
index bc271c8..5a8fd25 100644
--- a/services/surfaceflinger/EventThread.cpp
+++ b/services/surfaceflinger/EventThread.cpp
@@ -155,20 +155,17 @@
     mCondition.notify_all();
 }
 
-void EventThread::onHotplugReceived(int type, bool connected) {
-    ALOGE_IF(type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
-             "received hotplug event for an invalid display (id=%d)", type);
-
+void EventThread::onHotplugReceived(DisplayType displayType, bool connected) {
     std::lock_guard<std::mutex> lock(mMutex);
-    if (type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
-        DisplayEventReceiver::Event event;
-        event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
-        event.header.id = type;
-        event.header.timestamp = systemTime();
-        event.hotplug.connected = connected;
-        mPendingEvents.add(event);
-        mCondition.notify_all();
-    }
+
+    DisplayEventReceiver::Event event;
+    event.header.type = DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG;
+    event.header.id = displayType == DisplayType::Primary ? 0 : 1;
+    event.header.timestamp = systemTime();
+    event.hotplug.connected = connected;
+
+    mPendingEvents.add(event);
+    mCondition.notify_all();
 }
 
 void EventThread::threadMain() NO_THREAD_SAFETY_ANALYSIS {
@@ -205,7 +202,7 @@
 // This will return when (1) a vsync event has been received, and (2) there was
 // at least one connection interested in receiving it when we started waiting.
 Vector<sp<EventThread::Connection> > EventThread::waitForEventLocked(
-        std::unique_lock<std::mutex>* lock, DisplayEventReceiver::Event* event) {
+        std::unique_lock<std::mutex>* lock, DisplayEventReceiver::Event* outEvent) {
     Vector<sp<EventThread::Connection> > signalConnections;
 
     while (signalConnections.isEmpty() && mKeepRunning) {
@@ -214,16 +211,16 @@
 
         size_t vsyncCount = 0;
         nsecs_t timestamp = 0;
-        for (int32_t i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; i++) {
-            timestamp = mVSyncEvent[i].header.timestamp;
+        for (auto& event : mVSyncEvent) {
+            timestamp = event.header.timestamp;
             if (timestamp) {
                 // we have a vsync event to dispatch
                 if (mInterceptVSyncsCallback) {
                     mInterceptVSyncsCallback(timestamp);
                 }
-                *event = mVSyncEvent[i];
-                mVSyncEvent[i].header.timestamp = 0;
-                vsyncCount = mVSyncEvent[i].vsync.count;
+                *outEvent = event;
+                event.header.timestamp = 0;
+                vsyncCount = event.vsync.count;
                 break;
             }
         }
@@ -233,7 +230,7 @@
             eventPending = !mPendingEvents.isEmpty();
             if (eventPending) {
                 // we have some other event to dispatch
-                *event = mPendingEvents[0];
+                *outEvent = mPendingEvents[0];
                 mPendingEvents.removeAt(0);
             }
         }
@@ -319,7 +316,7 @@
                     // FIXME: how do we decide which display id the fake
                     // vsync came from ?
                     mVSyncEvent[0].header.type = DisplayEventReceiver::DISPLAY_EVENT_VSYNC;
-                    mVSyncEvent[0].header.id = DisplayDevice::DISPLAY_PRIMARY;
+                    mVSyncEvent[0].header.id = 0;
                     mVSyncEvent[0].header.timestamp = systemTime(SYSTEM_TIME_MONOTONIC);
                     mVSyncEvent[0].vsync.count++;
                 }
@@ -364,8 +361,7 @@
     result.appendFormat("VSYNC state: %s\n", mDebugVsyncEnabled ? "enabled" : "disabled");
     result.appendFormat("  soft-vsync: %s\n", mUseSoftwareVSync ? "enabled" : "disabled");
     result.appendFormat("  numListeners=%zu,\n  events-delivered: %u\n",
-                        mDisplayEventConnections.size(),
-                        mVSyncEvent[DisplayDevice::DISPLAY_PRIMARY].vsync.count);
+                        mDisplayEventConnections.size(), mVSyncEvent[0].vsync.count);
     for (size_t i = 0; i < mDisplayEventConnections.size(); i++) {
         sp<Connection> connection = mDisplayEventConnections.itemAt(i).promote();
         result.appendFormat("    %p: count=%d\n", connection.get(),
diff --git a/services/surfaceflinger/EventThread.h b/services/surfaceflinger/EventThread.h
index 9c13ed2..a0262b2 100644
--- a/services/surfaceflinger/EventThread.h
+++ b/services/surfaceflinger/EventThread.h
@@ -16,9 +16,11 @@
 
 #pragma once
 
-#include <stdint.h>
 #include <sys/types.h>
+
+#include <array>
 #include <condition_variable>
+#include <cstdint>
 #include <mutex>
 #include <thread>
 
@@ -31,8 +33,6 @@
 #include <utils/Errors.h>
 #include <utils/SortedVector.h>
 
-#include "DisplayDevice.h"
-
 // ---------------------------------------------------------------------------
 namespace android {
 // ---------------------------------------------------------------------------
@@ -59,6 +59,9 @@
 
 class EventThread {
 public:
+    // TODO: Remove once stable display IDs are plumbed through SF/WM interface.
+    enum class DisplayType { Primary, External };
+
     virtual ~EventThread();
 
     virtual sp<BnDisplayEventConnection> createEventConnection() const = 0;
@@ -70,7 +73,7 @@
     virtual void onScreenAcquired() = 0;
 
     // called when receiving a hotplug event
-    virtual void onHotplugReceived(int type, bool connected) = 0;
+    virtual void onHotplugReceived(DisplayType displayType, bool connected) = 0;
 
     virtual void dump(String8& result) const = 0;
 
@@ -122,7 +125,7 @@
     void onScreenAcquired() override;
 
     // called when receiving a hotplug event
-    void onHotplugReceived(int type, bool connected) override;
+    void onHotplugReceived(DisplayType displayType, bool connected) override;
 
     void dump(String8& result) const override;
 
@@ -155,8 +158,7 @@
     // protected by mLock
     SortedVector<wp<Connection>> mDisplayEventConnections GUARDED_BY(mMutex);
     Vector<DisplayEventReceiver::Event> mPendingEvents GUARDED_BY(mMutex);
-    DisplayEventReceiver::Event mVSyncEvent[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES] GUARDED_BY(
-            mMutex);
+    std::array<DisplayEventReceiver::Event, 2> mVSyncEvent GUARDED_BY(mMutex);
     bool mUseSoftwareVSync GUARDED_BY(mMutex) = false;
     bool mVsyncEnabled GUARDED_BY(mMutex) = false;
     bool mKeepRunning GUARDED_BY(mMutex) = true;
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index a14bb98..40d89bd 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -63,11 +63,6 @@
 
 namespace android {
 
-LayerBE::LayerBE()
-      : mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2) {
-}
-
-
 int32_t Layer::sSequence = 1;
 
 Layer::Layer(SurfaceFlinger* flinger, const sp<Client>& client, const String8& name, uint32_t w,
@@ -100,7 +95,9 @@
         mAutoRefresh(false),
         mFreezeGeometryUpdates(false),
         mCurrentChildren(LayerVector::StateSet::Current),
-        mDrawingChildren(LayerVector::StateSet::Drawing) {
+        mDrawingChildren(LayerVector::StateSet::Drawing),
+        mBE{this, name.string()} {
+
     mCurrentCrop.makeInvalid();
 
     uint32_t layerFlags = 0;
@@ -228,32 +225,32 @@
 // h/w composer set-up
 // ---------------------------------------------------------------------------
 
-bool Layer::createHwcLayer(HWComposer* hwc, int32_t hwcId) {
-    LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(hwcId) != 0,
-                        "Already have a layer for hwcId %d", hwcId);
-    HWC2::Layer* layer = hwc->createLayer(hwcId);
+bool Layer::createHwcLayer(HWComposer* hwc, int32_t displayId) {
+    LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(displayId) != 0,
+                        "Already have a layer for display %d", displayId);
+    HWC2::Layer* layer = hwc->createLayer(displayId);
     if (!layer) {
         return false;
     }
-    LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers[hwcId];
+    LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers[displayId];
     hwcInfo.hwc = hwc;
     hwcInfo.layer = layer;
     layer->setLayerDestroyedListener(
-            [this, hwcId](HWC2::Layer* /*layer*/) { getBE().mHwcLayers.erase(hwcId); });
+            [this, displayId](HWC2::Layer* /*layer*/) { getBE().mHwcLayers.erase(displayId); });
     return true;
 }
 
-bool Layer::destroyHwcLayer(int32_t hwcId) {
-    if (getBE().mHwcLayers.count(hwcId) == 0) {
+bool Layer::destroyHwcLayer(int32_t displayId) {
+    if (getBE().mHwcLayers.count(displayId) == 0) {
         return false;
     }
-    auto& hwcInfo = getBE().mHwcLayers[hwcId];
+    auto& hwcInfo = getBE().mHwcLayers[displayId];
     LOG_ALWAYS_FATAL_IF(hwcInfo.layer == nullptr, "Attempt to destroy null layer");
     LOG_ALWAYS_FATAL_IF(hwcInfo.hwc == nullptr, "Missing HWComposer");
-    hwcInfo.hwc->destroyLayer(hwcId, hwcInfo.layer);
+    hwcInfo.hwc->destroyLayer(displayId, hwcInfo.layer);
     // The layer destroyed listener should have cleared the entry from
     // mHwcLayers. Verify that.
-    LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(hwcId) != 0,
+    LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(displayId) != 0,
                         "Stale layer entry in getBE().mHwcLayers");
     return true;
 }
@@ -380,7 +377,7 @@
     return reduce(floatWin, activeTransparentRegion);
 }
 
-Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& hw) const {
+Rect Layer::computeInitialCrop(const sp<const DisplayDevice>& display) const {
     // the crop is the area of the window that gets cropped, but not
     // scaled in any ways.
     const State& s(getDrawingState());
@@ -399,7 +396,7 @@
 
     Transform t = getTransform();
     activeCrop = t.transform(activeCrop);
-    if (!activeCrop.intersect(hw->getViewport(), &activeCrop)) {
+    if (!activeCrop.intersect(display->getViewport(), &activeCrop)) {
         activeCrop.clear();
     }
     if (!s.finalCrop.isEmpty()) {
@@ -410,14 +407,14 @@
 
     const auto& p = mDrawingParent.promote();
     if (p != nullptr) {
-        auto parentCrop = p->computeInitialCrop(hw);
+        auto parentCrop = p->computeInitialCrop(display);
         activeCrop.intersect(parentCrop, &activeCrop);
     }
 
     return activeCrop;
 }
 
-FloatRect Layer::computeCrop(const sp<const DisplayDevice>& hw) const {
+FloatRect Layer::computeCrop(const sp<const DisplayDevice>& display) const {
     // the content crop is the area of the content that gets scaled to the
     // layer's size. This is in buffer space.
     FloatRect crop = getContentCrop().toFloatRect();
@@ -426,7 +423,7 @@
     const State& s(getDrawingState());
 
     // Screen space to make reduction to parent crop clearer.
-    Rect activeCrop = computeInitialCrop(hw);
+    Rect activeCrop = computeInitialCrop(display);
     Transform t = getTransform();
     // Back to layer space to work with the content crop.
     activeCrop = t.inverse().transform(activeCrop);
@@ -497,15 +494,19 @@
     return crop;
 }
 
-void Layer::setGeometry(const sp<const DisplayDevice>& displayDevice, uint32_t z)
-{
-    const auto hwcId = displayDevice->getHwcDisplayId();
-    auto& hwcInfo = getBE().mHwcLayers[hwcId];
+void Layer::setGeometry(const sp<const DisplayDevice>& display, uint32_t z) {
+    const auto displayId = display->getId();
+    if (!hasHwcLayer(displayId)) {
+        ALOGE("[%s] failed to setGeometry: no HWC layer found (%d)",
+              mName.string(), displayId);
+        return;
+    }
+    auto& hwcInfo = getBE().mHwcLayers[displayId];
 
     // enable this layer
     hwcInfo.forceClientComposition = false;
 
-    if (isSecure() && !displayDevice->isSecure()) {
+    if (isSecure() && !display->isSecure()) {
         hwcInfo.forceClientComposition = true;
     }
 
@@ -532,7 +533,7 @@
     if (!s.crop.isEmpty()) {
         Rect activeCrop(s.crop);
         activeCrop = t.transform(activeCrop);
-        if (!activeCrop.intersect(displayDevice->getViewport(), &activeCrop)) {
+        if (!activeCrop.intersect(display->getViewport(), &activeCrop)) {
             activeCrop.clear();
         }
         activeCrop = t.inverse().transform(activeCrop, true);
@@ -561,10 +562,10 @@
             frame.clear();
         }
     }
-    if (!frame.intersect(displayDevice->getViewport(), &frame)) {
+    if (!frame.intersect(display->getViewport(), &frame)) {
         frame.clear();
     }
-    const Transform& tr(displayDevice->getTransform());
+    const Transform& tr = display->getTransform();
     Rect transformedFrame = tr.transform(frame);
     error = hwcLayer->setDisplayFrame(transformedFrame);
     if (error != HWC2::Error::None) {
@@ -575,7 +576,7 @@
         hwcInfo.displayFrame = transformedFrame;
     }
 
-    FloatRect sourceCrop = computeCrop(displayDevice);
+    FloatRect sourceCrop = computeCrop(display);
     error = hwcLayer->setSourceCrop(sourceCrop);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
@@ -660,28 +661,28 @@
     }
 }
 
-void Layer::forceClientComposition(int32_t hwcId) {
-    if (getBE().mHwcLayers.count(hwcId) == 0) {
-        ALOGE("forceClientComposition: no HWC layer found (%d)", hwcId);
+void Layer::forceClientComposition(int32_t displayId) {
+    if (getBE().mHwcLayers.count(displayId) == 0) {
+        ALOGE("forceClientComposition: no HWC layer found (%d)", displayId);
         return;
     }
 
-    getBE().mHwcLayers[hwcId].forceClientComposition = true;
+    getBE().mHwcLayers[displayId].forceClientComposition = true;
 }
 
-bool Layer::getForceClientComposition(int32_t hwcId) {
-    if (getBE().mHwcLayers.count(hwcId) == 0) {
-        ALOGE("getForceClientComposition: no HWC layer found (%d)", hwcId);
+bool Layer::getForceClientComposition(int32_t displayId) {
+    if (getBE().mHwcLayers.count(displayId) == 0) {
+        ALOGE("getForceClientComposition: no HWC layer found (%d)", displayId);
         return false;
     }
 
-    return getBE().mHwcLayers[hwcId].forceClientComposition;
+    return getBE().mHwcLayers[displayId].forceClientComposition;
 }
 
-void Layer::updateCursorPosition(const sp<const DisplayDevice>& displayDevice) {
-    auto hwcId = displayDevice->getHwcDisplayId();
-    if (getBE().mHwcLayers.count(hwcId) == 0 ||
-        getCompositionType(hwcId) != HWC2::Composition::Cursor) {
+void Layer::updateCursorPosition(const sp<const DisplayDevice>& display) {
+    const auto displayId = display->getId();
+    if (getBE().mHwcLayers.count(displayId) == 0 ||
+        getCompositionType(displayId) != HWC2::Composition::Cursor) {
         return;
     }
 
@@ -697,15 +698,15 @@
     // Subtract the transparent region and snap to the bounds
     Rect bounds = reduce(win, s.activeTransparentRegion);
     Rect frame(getTransform().transform(bounds));
-    frame.intersect(displayDevice->getViewport(), &frame);
+    frame.intersect(display->getViewport(), &frame);
     if (!s.finalCrop.isEmpty()) {
         frame.intersect(s.finalCrop, &frame);
     }
-    auto& displayTransform(displayDevice->getTransform());
+    auto& displayTransform = display->getTransform();
     auto position = displayTransform.transform(frame);
 
-    auto error = getBE().mHwcLayers[hwcId].layer->setCursorPosition(position.left,
-                                                                              position.top);
+    auto error =
+            getBE().mHwcLayers[displayId].layer->setCursorPosition(position.left, position.top);
     ALOGE_IF(error != HWC2::Error::None,
              "[%s] Failed to set cursor position "
              "to (%d, %d): %s (%d)",
@@ -741,12 +742,12 @@
     clearWithOpenGL(renderArea, 0, 0, 0, 0);
 }
 
-void Layer::setCompositionType(int32_t hwcId, HWC2::Composition type, bool callIntoHwc) {
-    if (getBE().mHwcLayers.count(hwcId) == 0) {
+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;
     }
-    auto& hwcInfo = getBE().mHwcLayers[hwcId];
+    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));
@@ -764,33 +765,33 @@
     }
 }
 
-HWC2::Composition Layer::getCompositionType(int32_t hwcId) const {
-    if (hwcId == DisplayDevice::DISPLAY_ID_INVALID) {
+HWC2::Composition Layer::getCompositionType(int32_t displayId) const {
+    if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
         // If we're querying the composition type for a display that does not
         // have a HWC counterpart, then it will always be Client
         return HWC2::Composition::Client;
     }
-    if (getBE().mHwcLayers.count(hwcId) == 0) {
+    if (getBE().mHwcLayers.count(displayId) == 0) {
         ALOGE("getCompositionType called with an invalid HWC layer");
         return HWC2::Composition::Invalid;
     }
-    return getBE().mHwcLayers.at(hwcId).compositionType;
+    return getBE().mHwcLayers.at(displayId).compositionType;
 }
 
-void Layer::setClearClientTarget(int32_t hwcId, bool clear) {
-    if (getBE().mHwcLayers.count(hwcId) == 0) {
+void Layer::setClearClientTarget(int32_t displayId, bool clear) {
+    if (getBE().mHwcLayers.count(displayId) == 0) {
         ALOGE("setClearClientTarget called without a valid HWC layer");
         return;
     }
-    getBE().mHwcLayers[hwcId].clearClientTarget = clear;
+    getBE().mHwcLayers[displayId].clearClientTarget = clear;
 }
 
-bool Layer::getClearClientTarget(int32_t hwcId) const {
-    if (getBE().mHwcLayers.count(hwcId) == 0) {
+bool Layer::getClearClientTarget(int32_t displayId) const {
+    if (getBE().mHwcLayers.count(displayId) == 0) {
         ALOGE("getClearClientTarget called without a valid HWC layer");
         return false;
     }
-    return getBE().mHwcLayers.at(hwcId).clearClientTarget;
+    return getBE().mHwcLayers.at(displayId).clearClientTarget;
 }
 
 bool Layer::addSyncPoint(const std::shared_ptr<SyncPoint>& point) {
@@ -1397,13 +1398,13 @@
     return usage;
 }
 
-void Layer::updateTransformHint(const sp<const DisplayDevice>& hw) const {
+void Layer::updateTransformHint(const sp<const DisplayDevice>& display) const {
     uint32_t orientation = 0;
     if (!mFlinger->mDebugDisableTransformHint) {
         // The transform hint is used to improve performance, but we can
         // only have a single transform hint, it cannot
         // apply to all displays.
-        const Transform& planeTransform(hw->getTransform());
+        const Transform& planeTransform = display->getTransform();
         orientation = planeTransform.getOrientation();
         if (orientation & Transform::ROT_INVALID) {
             orientation = 0;
@@ -1443,7 +1444,7 @@
     info.mMatrix[1][0] = ds.active.transform[1][0];
     info.mMatrix[1][1] = ds.active.transform[1][1];
     {
-        sp<const GraphicBuffer> buffer = getBE().compositionInfo.mBuffer;
+        sp<const GraphicBuffer> buffer = mActiveBuffer;
         if (buffer != 0) {
             info.mActiveBufferWidth = buffer->getWidth();
             info.mActiveBufferHeight = buffer->getHeight();
@@ -1464,19 +1465,22 @@
 }
 
 void Layer::miniDumpHeader(String8& result) {
-    result.append("----------------------------------------");
-    result.append("---------------------------------------\n");
+    result.append("-------------------------------");
+    result.append("-------------------------------");
+    result.append("-----------------------------\n");
     result.append(" Layer name\n");
     result.append("           Z | ");
     result.append(" Comp Type | ");
+    result.append(" Transform | ");
     result.append("  Disp Frame (LTRB) | ");
     result.append("         Source Crop (LTRB)\n");
-    result.append("----------------------------------------");
-    result.append("---------------------------------------\n");
+    result.append("-------------------------------");
+    result.append("-------------------------------");
+    result.append("-----------------------------\n");
 }
 
-void Layer::miniDump(String8& result, int32_t hwcId) const {
-    if (getBE().mHwcLayers.count(hwcId) == 0) {
+void Layer::miniDump(String8& result, int32_t displayId) const {
+    if (getBE().mHwcLayers.count(displayId) == 0) {
         return;
     }
 
@@ -1494,20 +1498,22 @@
     result.appendFormat(" %s\n", name.string());
 
     const Layer::State& layerState(getDrawingState());
-    const LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers.at(hwcId);
+    const LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers.at(displayId);
     if (layerState.zOrderRelativeOf != nullptr || mDrawingParent != nullptr) {
         result.appendFormat("  rel %6d | ", layerState.z);
     } else {
         result.appendFormat("  %10d | ", layerState.z);
     }
-    result.appendFormat("%10s | ", to_string(getCompositionType(hwcId)).c_str());
+    result.appendFormat("%10s | ", to_string(getCompositionType(displayId)).c_str());
+    result.appendFormat("%10s | ", to_string(hwcInfo.transform).c_str());
     const Rect& frame = hwcInfo.displayFrame;
     result.appendFormat("%4d %4d %4d %4d | ", frame.left, frame.top, frame.right, frame.bottom);
     const FloatRect& crop = hwcInfo.sourceCrop;
     result.appendFormat("%6.1f %6.1f %6.1f %6.1f\n", crop.left, crop.top, crop.right, crop.bottom);
 
-    result.append("- - - - - - - - - - - - - - - - - - - - ");
-    result.append("- - - - - - - - - - - - - - - - - - - -\n");
+    result.append("- - - - - - - - - - - - - - - -");
+    result.append("- - - - - - - - - - - - - - - -");
+    result.append("- - - - - - - - - - - - - - -\n");
 }
 
 void Layer::dumpFrameStats(String8& result) const {
@@ -1990,6 +1996,8 @@
     auto buffer = getBE().compositionInfo.mBuffer;
     if (buffer != nullptr) {
         LayerProtoHelper::writeToProto(buffer, layerInfo->mutable_active_buffer());
+        LayerProtoHelper::writeToProto(Transform(mCurrentTransform),
+                                       layerInfo->mutable_buffer_transform());
     }
 
     layerInfo->set_queued_frames(getQueuedFrameCount());
@@ -2008,10 +2016,14 @@
     }
 }
 
-void Layer::writeToProto(LayerProto* layerInfo, int32_t hwcId) {
+void Layer::writeToProto(LayerProto* layerInfo, int32_t displayId) {
+    if (!hasHwcLayer(displayId)) {
+        return;
+    }
+
     writeToProto(layerInfo, LayerVector::StateSet::Drawing);
 
-    const auto& hwcInfo = getBE().mHwcLayers.at(hwcId);
+    const auto& hwcInfo = getBE().mHwcLayers.at(displayId);
 
     const Rect& frame = hwcInfo.displayFrame;
     LayerProtoHelper::writeToProto(frame, layerInfo->mutable_hwc_frame());
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 2239679..f724096 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -38,6 +38,7 @@
 
 #include "Client.h"
 #include "FrameTracker.h"
+#include "LayerBE.h"
 #include "LayerVector.h"
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
@@ -74,70 +75,6 @@
 
 // ---------------------------------------------------------------------------
 
-struct CompositionInfo {
-    HWC2::Composition compositionType;
-    sp<GraphicBuffer> mBuffer = nullptr;
-    int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
-    struct {
-        HWComposer* hwc;
-        sp<Fence> fence;
-        HWC2::BlendMode blendMode;
-        Rect displayFrame;
-        float alpha;
-        FloatRect sourceCrop;
-        HWC2::Transform transform;
-        int z;
-        int type;
-        int appId;
-        Region visibleRegion;
-        Region surfaceDamage;
-        sp<NativeHandle> sidebandStream;
-        android_dataspace dataspace;
-        hwc_color_t color;
-    } hwc;
-    struct {
-        RE::RenderEngine* renderEngine;
-        Mesh* mesh;
-    } renderEngine;
-};
-
-class LayerBE {
-public:
-    LayerBE();
-
-    // The mesh used to draw the layer in GLES composition mode
-    Mesh mMesh;
-
-    // HWC items, accessed from the main thread
-    struct HWCInfo {
-        HWCInfo()
-              : hwc(nullptr),
-                layer(nullptr),
-                forceClientComposition(false),
-                compositionType(HWC2::Composition::Invalid),
-                clearClientTarget(false),
-                transform(HWC2::Transform::None) {}
-
-        HWComposer* hwc;
-        HWC2::Layer* layer;
-        bool forceClientComposition;
-        HWC2::Composition compositionType;
-        bool clearClientTarget;
-        Rect displayFrame;
-        FloatRect sourceCrop;
-        HWComposerBufferCache bufferCache;
-        HWC2::Transform transform;
-    };
-
-    // A layer can be attached to multiple displays when operating in mirror mode
-    // (a.k.a: when several displays are attached with equal layerStack). In this
-    // case we need to keep track. In non-mirror mode, a layer will have only one
-    // HWCInfo. This map key is a display layerStack.
-    std::unordered_map<int32_t, HWCInfo> mHwcLayers;
-
-    CompositionInfo compositionInfo;
-};
-
 class Layer : public virtual RefBase {
     static int32_t sSequence;
 
@@ -371,7 +308,7 @@
     void writeToProto(LayerProto* layerInfo,
                       LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
 
-    void writeToProto(LayerProto* layerInfo, int32_t hwcId);
+    void writeToProto(LayerProto* layerInfo, int32_t displayId);
 
 protected:
     /*
@@ -385,18 +322,18 @@
 
     virtual bool isHdrY410() const { return false; }
 
-    void setGeometry(const sp<const DisplayDevice>& displayDevice, uint32_t z);
-    void forceClientComposition(int32_t hwcId);
-    bool getForceClientComposition(int32_t hwcId);
-    virtual void setPerFrameData(const sp<const DisplayDevice>& displayDevice) = 0;
+    void setGeometry(const sp<const DisplayDevice>& display, uint32_t z);
+    void forceClientComposition(int32_t displayId);
+    bool getForceClientComposition(int32_t displayId);
+    virtual void setPerFrameData(const sp<const DisplayDevice>& display) = 0;
 
     // callIntoHwc exists so we can update our local state and call
     // acceptDisplayChanges without unnecessarily updating the device's state
-    void setCompositionType(int32_t hwcId, HWC2::Composition type, bool callIntoHwc = true);
-    HWC2::Composition getCompositionType(int32_t hwcId) const;
-    void setClearClientTarget(int32_t hwcId, bool clear);
-    bool getClearClientTarget(int32_t hwcId) const;
-    void updateCursorPosition(const sp<const DisplayDevice>& hw);
+    void setCompositionType(int32_t displayId, HWC2::Composition type, bool callIntoHwc = true);
+    HWC2::Composition getCompositionType(int32_t displayId) const;
+    void setClearClientTarget(int32_t displayId, bool clear);
+    bool getClearClientTarget(int32_t displayId) const;
+    void updateCursorPosition(const sp<const DisplayDevice>& display);
 
     /*
      * called after page-flip
@@ -437,6 +374,16 @@
     void draw(const RenderArea& renderArea) const;
 
     /*
+     * drawNow uses the renderEngine to draw the layer.  This is different than the
+     * draw function as with the FE/BE split, the draw function runs in the FE and
+     * sets up state for the BE to do the actual drawing.  drawNow is used to tell
+     * the layer to skip the state setup and just go ahead and draw the layer.  This
+     * is used for screen captures which happens separately from the frame
+     * compositing path.
+     */
+    virtual void drawNow(const RenderArea& renderArea, bool useIdentityTransform) const = 0;
+
+    /*
      * doTransaction - process the transaction. This is a good place to figure
      * out which attributes of the surface have changed.
      */
@@ -493,7 +440,7 @@
 
     // Updates the transform hint in our SurfaceFlingerConsumer to match
     // the current orientation of the display device.
-    void updateTransformHint(const sp<const DisplayDevice>& hw) const;
+    void updateTransformHint(const sp<const DisplayDevice>& display) const;
 
     /*
      * returns the rectangle that crops the content of the layer and scales it
@@ -512,19 +459,17 @@
 
     // -----------------------------------------------------------------------
 
-    bool createHwcLayer(HWComposer* hwc, int32_t hwcId);
-    bool destroyHwcLayer(int32_t hwcId);
+    bool createHwcLayer(HWComposer* hwc, int32_t displayId);
+    bool destroyHwcLayer(int32_t displayId);
     void destroyAllHwcLayers();
 
-    bool hasHwcLayer(int32_t hwcId) {
-        return getBE().mHwcLayers.count(hwcId) > 0;
-    }
+    bool hasHwcLayer(int32_t displayId) { return getBE().mHwcLayers.count(displayId) > 0; }
 
-    HWC2::Layer* getHwcLayer(int32_t hwcId) {
-        if (getBE().mHwcLayers.count(hwcId) == 0) {
+    HWC2::Layer* getHwcLayer(int32_t displayId) {
+        if (getBE().mHwcLayers.count(displayId) == 0) {
             return nullptr;
         }
-        return getBE().mHwcLayers[hwcId].layer;
+        return getBE().mHwcLayers[displayId].layer;
     }
 
     // -----------------------------------------------------------------------
@@ -542,7 +487,7 @@
 
     /* always call base class first */
     static void miniDumpHeader(String8& result);
-    void miniDump(String8& result, int32_t hwcId) const;
+    void miniDump(String8& result, int32_t displayId) const;
     void dumpFrameStats(String8& result) const;
     void dumpFrameEvents(String8& result);
     void clearFrameStats();
@@ -626,12 +571,12 @@
 
     uint32_t getEffectiveUsage(uint32_t usage) const;
 
-    FloatRect computeCrop(const sp<const DisplayDevice>& hw) const;
+    virtual FloatRect computeCrop(const sp<const DisplayDevice>& display) const;
     // Compute the initial crop as specified by parent layers and the
     // SurfaceControl for this layer. Does not include buffer crop from the
     // IGraphicBufferProducer client, as that should not affect child clipping.
     // Returns in screen space.
-    Rect computeInitialCrop(const sp<const DisplayDevice>& hw) const;
+    Rect computeInitialCrop(const sp<const DisplayDevice>& display) const;
 
     // drawing
     void clearWithOpenGL(const RenderArea& renderArea, float r, float g, float b,
diff --git a/services/surfaceflinger/LayerBE.cpp b/services/surfaceflinger/LayerBE.cpp
new file mode 100644
index 0000000..51b615b
--- /dev/null
+++ b/services/surfaceflinger/LayerBE.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "LayerBE"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "Layer.h"
+
+namespace android {
+
+LayerBE::LayerBE(Layer* layer, std::string layerName)
+      : mLayer(layer),
+        mMesh(Mesh::TRIANGLE_FAN, 4, 2, 2) {
+    compositionInfo.layer = this;
+    compositionInfo.layerName = layerName;
+}
+
+void LayerBE::onLayerDisplayed(const sp<Fence>& releaseFence) {
+    mLayer->onLayerDisplayed(releaseFence);
+}
+
+void CompositionInfo::dumpHwc(const char* tag) const {
+    ALOGV("[%s]\thwcLayer=%p", tag, hwc.hwcLayer);
+    ALOGV("[%s]\tfence=%p", tag, hwc.fence.get());
+    ALOGV("[%s]\ttransform=%d", tag, hwc.transform);
+    ALOGV("[%s]\tz=%d", tag, hwc.z);
+    ALOGV("[%s]\ttype=%d", tag, hwc.type);
+    ALOGV("[%s]\tappId=%d", tag, hwc.appId);
+    ALOGV("[%s]\tdisplayFrame=%4d %4d %4d %4d", tag, hwc.displayFrame.left, hwc.displayFrame.top, hwc.displayFrame.right, hwc.displayFrame.bottom);
+    ALOGV("[%s]\talpha=%.3f", tag, hwc.alpha);
+    ALOGV("[%s]\tsourceCrop=%6.1f %6.1f %6.1f %6.1f", tag, hwc.sourceCrop.left, hwc.sourceCrop.top, hwc.sourceCrop.right, hwc.sourceCrop.bottom);
+
+    std::string label = tag;
+    label+=":visibleRegion";
+    hwc.visibleRegion.dump(label.c_str());
+    label = tag;
+    label+=":surfaceDamage";
+    hwc.surfaceDamage.dump(label.c_str());
+}
+
+void CompositionInfo::dumpRe(const char* tag) const {
+    ALOGV("[%s]\tblackoutLayer=%d", tag, re.blackoutLayer);
+    ALOGV("[%s]\tclearArea=%d", tag, re.clearArea);
+    ALOGV("[%s]\tpreMultipliedAlpha=%d", tag, re.preMultipliedAlpha);
+    ALOGV("[%s]\topaque=%d", tag, re.opaque);
+    ALOGV("[%s]\tdisableTexture=%d", tag, re.disableTexture);
+    ALOGV("[%s]\ttexture:name(%d), target(%d), size(%d/%d)", tag, re.texture.getTextureName(), re.texture.getTextureTarget(), (unsigned int)re.texture.getWidth(), (unsigned int)re.texture.getHeight());
+    ALOGV("[%s]\tuseIdentityTransform=%d\n", tag, re.useIdentityTransform);
+}
+
+void CompositionInfo::dump(const char* tag) const {
+    ALOGV("[%s] CompositionInfo", tag);
+    ALOGV("[%s]\tLayerName: %s", tag, layerName.c_str());
+    ALOGV("[%s]\tCompositionType: %d", tag, compositionType);
+    ALOGV("[%s]\tmBuffer = %p", tag, mBuffer.get());
+    ALOGV("[%s]\tmBufferSlot=%d", tag, mBufferSlot);
+    switch (compositionType) {
+        case HWC2::Composition::Device:
+            dumpHwc(tag);
+            break;
+        case HWC2::Composition::Client:
+            dumpRe(tag);
+        default:
+            break;
+    }
+}
+
+}; // namespace android
diff --git a/services/surfaceflinger/LayerBE.h b/services/surfaceflinger/LayerBE.h
new file mode 100644
index 0000000..9aa43f7
--- /dev/null
+++ b/services/surfaceflinger/LayerBE.h
@@ -0,0 +1,125 @@
+/*
+ * Copyright (C) 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 <stdint.h>
+#include <sys/types.h>
+
+#include <ui/Region.h>
+
+#include "SurfaceFlinger.h"
+
+#include "DisplayHardware/HWComposer.h"
+#include "DisplayHardware/HWComposerBufferCache.h"
+#include "RenderEngine/Mesh.h"
+#include "RenderEngine/Texture.h"
+
+namespace android {
+
+class LayerBE;
+
+struct CompositionInfo {
+    std::string layerName;
+    HWC2::Composition compositionType;
+    sp<GraphicBuffer> mBuffer = nullptr;
+    int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
+    LayerBE* layer = nullptr;
+    struct {
+        HWC2::Layer* hwcLayer;
+        sp<Fence> fence;
+        HWC2::BlendMode blendMode = HWC2::BlendMode::Invalid;
+        Rect displayFrame;
+        float alpha;
+        FloatRect sourceCrop;
+        HWC2::Transform transform = HWC2::Transform::None;
+        int z;
+        int type;
+        int appId;
+        Region visibleRegion;
+        Region surfaceDamage;
+        sp<NativeHandle> sidebandStream;
+        ui::Dataspace dataspace;
+        hwc_color_t color;
+    } hwc;
+    struct {
+        Mesh* mesh;
+        bool blackoutLayer = false;
+        bool clearArea = false;
+        bool preMultipliedAlpha = false;
+        bool opaque = false;
+        bool disableTexture = false;
+        half4 color;
+        Texture texture;
+        bool useIdentityTransform = false;
+        bool Y410BT2020 = false;
+    } re;
+
+    void dump(const char* tag) const;
+    void dumpHwc(const char* tag) const;
+    void dumpRe(const char* tag) const;
+};
+
+class LayerBE {
+public:
+    friend class Layer;
+    friend class BufferLayer;
+    friend class ColorLayer;
+    friend class SurfaceFlinger;
+
+    LayerBE(Layer* layer, std::string layerName);
+
+    void onLayerDisplayed(const sp<Fence>& releaseFence);
+    Mesh& getMesh() { return mMesh; }
+
+private:
+    Layer*const mLayer;
+    // The mesh used to draw the layer in GLES composition mode
+    Mesh mMesh;
+
+    // HWC items, accessed from the main thread
+    struct HWCInfo {
+        HWCInfo()
+              : hwc(nullptr),
+                layer(nullptr),
+                forceClientComposition(false),
+                compositionType(HWC2::Composition::Invalid),
+                clearClientTarget(false),
+                transform(HWC2::Transform::None) {}
+
+        HWComposer* hwc;
+        HWC2::Layer* layer;
+        bool forceClientComposition;
+        HWC2::Composition compositionType;
+        bool clearClientTarget;
+        Rect displayFrame;
+        FloatRect sourceCrop;
+        HWComposerBufferCache bufferCache;
+        HWC2::Transform transform;
+    };
+
+
+    // A layer can be attached to multiple displays when operating in mirror mode
+    // (a.k.a: when several displays are attached with equal layerStack). In this
+    // case we need to keep track. In non-mirror mode, a layer will have only one
+    // HWCInfo. This map key is a display layerStack.
+    std::unordered_map<int32_t, HWCInfo> mHwcLayers;
+
+    CompositionInfo compositionInfo;
+};
+
+}; // namespace android
+
diff --git a/services/surfaceflinger/LayerRejecter.cpp b/services/surfaceflinger/LayerRejecter.cpp
index a5f0b98..381ea4a 100644
--- a/services/surfaceflinger/LayerRejecter.cpp
+++ b/services/surfaceflinger/LayerRejecter.cpp
@@ -31,6 +31,7 @@
                              bool stickySet,
                              const char* name,
                              int32_t overrideScalingMode,
+                             bool transformToDisplayInverse,
                              bool& freezePositionUpdates)
   : mFront(front),
     mCurrent(current),
@@ -38,6 +39,7 @@
     mStickyTransformSet(stickySet),
     mName(name),
     mOverrideScalingMode(overrideScalingMode),
+    mTransformToDisplayInverse(transformToDisplayInverse),
     mFreezeGeometryUpdates(freezePositionUpdates) {}
 
 bool LayerRejecter::reject(const sp<GraphicBuffer>& buf, const BufferItem& item) {
@@ -54,6 +56,13 @@
         swap(bufWidth, bufHeight);
     }
 
+    if (mTransformToDisplayInverse) {
+        uint32_t invTransform = DisplayDevice::getPrimaryDisplayOrientationTransform();
+        if (invTransform & Transform::ROT_90) {
+            swap(bufWidth, bufHeight);
+        }
+    }
+
     int actualScalingMode = mOverrideScalingMode >= 0 ? mOverrideScalingMode : item.mScalingMode;
     bool isFixedSize = actualScalingMode != NATIVE_WINDOW_SCALING_MODE_FREEZE;
     if (mFront.active != mFront.requested) {
diff --git a/services/surfaceflinger/LayerRejecter.h b/services/surfaceflinger/LayerRejecter.h
index 40972aa..63d51de 100644
--- a/services/surfaceflinger/LayerRejecter.h
+++ b/services/surfaceflinger/LayerRejecter.h
@@ -29,6 +29,7 @@
                       bool stickySet,
                       const char *name,
                       int32_t overrideScalingMode,
+                      bool transformToDisplayInverse,
                       bool &freezePositionUpdates);
 
         virtual bool reject(const sp<GraphicBuffer> &buf, const BufferItem &item);
@@ -40,6 +41,7 @@
         bool mStickyTransformSet;
         const char *mName;
         int32_t mOverrideScalingMode;
+        bool mTransformToDisplayInverse;
         bool &mFreezeGeometryUpdates;
     };
 }  // namespace android
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.cpp b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
index dc09a37..23480b4 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.cpp
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.cpp
@@ -99,10 +99,6 @@
     if (hasEGLExtension("EGL_KHR_wait_sync")) {
         mHasWaitSync = true;
     }
-
-    if (hasEGLExtension("EGL_ANDROID_image_crop")) {
-        mHasImageCrop = true;
-    }
     if (hasEGLExtension("EGL_EXT_protected_content")) {
         mHasProtectedContent = true;
     }
diff --git a/services/surfaceflinger/RenderEngine/GLExtensions.h b/services/surfaceflinger/RenderEngine/GLExtensions.h
index 0d8c10b..a6a5053 100644
--- a/services/surfaceflinger/RenderEngine/GLExtensions.h
+++ b/services/surfaceflinger/RenderEngine/GLExtensions.h
@@ -39,7 +39,6 @@
     bool mHasNativeFenceSync = false;
     bool mHasFenceSync = false;
     bool mHasWaitSync = false;
-    bool mHasImageCrop = false;
     bool mHasProtectedContent = false;
     bool mHasContextPriority = false;
 
@@ -66,7 +65,6 @@
     bool hasNativeFenceSync() const { return mHasNativeFenceSync; }
     bool hasFenceSync() const { return mHasFenceSync; }
     bool hasWaitSync() const { return mHasWaitSync; }
-    bool hasImageCrop() const { return mHasImageCrop; }
     bool hasProtectedContent() const { return mHasProtectedContent; }
     bool hasContextPriority() const { return mHasContextPriority; }
 
diff --git a/services/surfaceflinger/RenderEngine/Image.cpp b/services/surfaceflinger/RenderEngine/Image.cpp
index 0d06422..6e0a880 100644
--- a/services/surfaceflinger/RenderEngine/Image.cpp
+++ b/services/surfaceflinger/RenderEngine/Image.cpp
@@ -33,11 +33,10 @@
 Image::Image(const RenderEngine& engine) : mEGLDisplay(engine.getEGLDisplay()) {}
 
 Image::~Image() {
-    setNativeWindowBuffer(nullptr, false, 0, 0);
+    setNativeWindowBuffer(nullptr, false);
 }
 
-static std::vector<EGLint> buildAttributeList(bool isProtected, int32_t cropWidth,
-                                              int32_t cropHeight) {
+static std::vector<EGLint> buildAttributeList(bool isProtected) {
     std::vector<EGLint> attrs;
     attrs.reserve(16);
 
@@ -49,24 +48,12 @@
         attrs.push_back(EGL_TRUE);
     }
 
-    if (cropWidth > 0 && cropHeight > 0) {
-        attrs.push_back(EGL_IMAGE_CROP_LEFT_ANDROID);
-        attrs.push_back(0);
-        attrs.push_back(EGL_IMAGE_CROP_TOP_ANDROID);
-        attrs.push_back(0);
-        attrs.push_back(EGL_IMAGE_CROP_RIGHT_ANDROID);
-        attrs.push_back(cropWidth);
-        attrs.push_back(EGL_IMAGE_CROP_BOTTOM_ANDROID);
-        attrs.push_back(cropHeight);
-    }
-
     attrs.push_back(EGL_NONE);
 
     return attrs;
 }
 
-bool Image::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
-                                  int32_t cropHeight) {
+bool Image::setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) {
     if (mEGLImage != EGL_NO_IMAGE_KHR) {
         if (!eglDestroyImageKHR(mEGLDisplay, mEGLImage)) {
             ALOGE("failed to destroy image: %#x", eglGetError());
@@ -75,7 +62,7 @@
     }
 
     if (buffer) {
-        std::vector<EGLint> attrs = buildAttributeList(isProtected, cropWidth, cropHeight);
+        std::vector<EGLint> attrs = buildAttributeList(isProtected);
         mEGLImage = eglCreateImageKHR(mEGLDisplay, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
                                       static_cast<EGLClientBuffer>(buffer), attrs.data());
         if (mEGLImage == EGL_NO_IMAGE_KHR) {
diff --git a/services/surfaceflinger/RenderEngine/Image.h b/services/surfaceflinger/RenderEngine/Image.h
index 1ae7e09..c38fe0a 100644
--- a/services/surfaceflinger/RenderEngine/Image.h
+++ b/services/surfaceflinger/RenderEngine/Image.h
@@ -29,8 +29,7 @@
 class Image {
 public:
     virtual ~Image() = 0;
-    virtual bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected,
-                                       int32_t cropWidth, int32_t cropHeight) = 0;
+    virtual bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) = 0;
 };
 
 namespace impl {
@@ -45,8 +44,7 @@
     Image(const Image&) = delete;
     Image& operator=(const Image&) = delete;
 
-    bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
-                               int32_t cropHeight) override;
+    bool setNativeWindowBuffer(ANativeWindowBuffer* buffer, bool isProtected) override;
 
 private:
     // methods internal to RenderEngine
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index d745770..0b8b838 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -175,10 +175,6 @@
     return mEGLConfig;
 }
 
-bool RenderEngine::supportsImageCrop() const {
-    return GLExtensions::getInstance().hasImageCrop();
-}
-
 bool RenderEngine::isCurrent() const {
     return mEGLDisplay == eglGetCurrentDisplay() && mEGLContext == eglGetCurrentContext();
 }
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 1786155..95b9ec8 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -69,8 +69,6 @@
     // dump the extension strings. always call the base class.
     virtual void dump(String8& result) = 0;
 
-    virtual bool supportsImageCrop() const = 0;
-
     virtual bool isCurrent() const = 0;
     virtual bool setCurrentSurface(const RE::Surface& surface) = 0;
     virtual void resetCurrentSurface() = 0;
@@ -192,8 +190,6 @@
     // dump the extension strings. always call the base class.
     void dump(String8& result) override;
 
-    bool supportsImageCrop() const override;
-
     bool isCurrent() const;
     bool setCurrentSurface(const RE::Surface& surface) override;
     void resetCurrentSurface() override;
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index cf53930..ba5154d 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -79,6 +79,7 @@
 #include "clz.h"
 
 #include "DisplayHardware/ComposerHal.h"
+#include "DisplayHardware/DisplayIdentification.h"
 #include "DisplayHardware/FramebufferSurface.h"
 #include "DisplayHardware/HWComposer.h"
 #include "DisplayHardware/VirtualDisplaySurface.h"
@@ -113,6 +114,33 @@
 using ui::RenderIntent;
 
 namespace {
+
+#pragma clang diagnostic push
+#pragma clang diagnostic error "-Wswitch-enum"
+
+bool isWideColorMode(const ColorMode colorMode) {
+    switch (colorMode) {
+        case ColorMode::DISPLAY_P3:
+        case ColorMode::ADOBE_RGB:
+        case ColorMode::DCI_P3:
+        case ColorMode::BT2020:
+        case ColorMode::BT2100_PQ:
+        case ColorMode::BT2100_HLG:
+            return true;
+        case ColorMode::NATIVE:
+        case ColorMode::STANDARD_BT601_625:
+        case ColorMode::STANDARD_BT601_625_UNADJUSTED:
+        case ColorMode::STANDARD_BT601_525:
+        case ColorMode::STANDARD_BT601_525_UNADJUSTED:
+        case ColorMode::STANDARD_BT709:
+        case ColorMode::SRGB:
+            return false;
+    }
+    return false;
+}
+
+#pragma clang diagnostic pop
+
 class ConditionalLock {
 public:
     ConditionalLock(Mutex& mutex, bool lock) : mMutex(mutex), mLocked(lock) {
@@ -125,6 +153,7 @@
     Mutex& mMutex;
     bool mLocked;
 };
+
 }  // namespace anonymous
 
 // ---------------------------------------------------------------------------
@@ -219,7 +248,7 @@
         mLayersAdded(false),
         mRepaintEverything(0),
         mBootTime(systemTime()),
-        mBuiltinDisplays(),
+        mDisplayTokens(),
         mVisibleRegionsDirty(false),
         mGeometryInvalid(false),
         mAnimCompositionPending(false),
@@ -322,7 +351,7 @@
 
     property_get("debug.sf.enable_hwc_vds", value, "0");
     mUseHwcVirtualDisplays = atoi(value);
-    ALOGI_IF(!mUseHwcVirtualDisplays, "Enabling HWC virtual displays");
+    ALOGI_IF(mUseHwcVirtualDisplays, "Enabling HWC virtual displays");
 
     property_get("ro.sf.disable_triple_buffer", value, "1");
     mLayerTripleBufferingDisabled = atoi(value);
@@ -433,28 +462,30 @@
     sp<BBinder> token = new DisplayToken(this);
 
     Mutex::Autolock _l(mStateLock);
-    DisplayDeviceState info(DisplayDevice::DISPLAY_VIRTUAL, secure);
+    DisplayDeviceState info;
+    info.type = DisplayDevice::DISPLAY_VIRTUAL;
     info.displayName = displayName;
+    info.isSecure = secure;
     mCurrentState.displays.add(token, info);
     mInterceptor->saveDisplayCreation(info);
     return token;
 }
 
-void SurfaceFlinger::destroyDisplay(const sp<IBinder>& display) {
+void SurfaceFlinger::destroyDisplay(const sp<IBinder>& displayToken) {
     Mutex::Autolock _l(mStateLock);
 
-    ssize_t idx = mCurrentState.displays.indexOfKey(display);
+    ssize_t idx = mCurrentState.displays.indexOfKey(displayToken);
     if (idx < 0) {
-        ALOGW("destroyDisplay: invalid display token");
+        ALOGE("destroyDisplay: Invalid display token %p", displayToken.get());
         return;
     }
 
     const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
-    if (!info.isVirtualDisplay()) {
+    if (!info.isVirtual()) {
         ALOGE("destroyDisplay called for non-virtual display");
         return;
     }
-    mInterceptor->saveDisplayDeletion(info.displayId);
+    mInterceptor->saveDisplayDeletion(info.sequenceId);
     mCurrentState.displays.removeItemsAt(idx);
     setTransactionFlags(eDisplayTransactionNeeded);
 }
@@ -464,7 +495,7 @@
         ALOGE("getDefaultDisplay: id=%d is not a valid default display id", id);
         return nullptr;
     }
-    return mBuiltinDisplays[id];
+    return mDisplayTokens[id];
 }
 
 void SurfaceFlinger::bootFinished()
@@ -496,11 +527,10 @@
     LOG_EVENT_LONG(LOGTAG_SF_STOP_BOOTANIM,
                    ns2ms(systemTime(SYSTEM_TIME_MONOTONIC)));
 
-    sp<LambdaMessage> readProperties = new LambdaMessage([&]() {
+    postMessageAsync(new LambdaMessage([this] {
         readPersistentProperties();
         mBootStage = BootStage::FINISHED;
-    });
-    postMessageAsync(readProperties);
+    }));
 }
 
 uint32_t SurfaceFlinger::getNewTexture() {
@@ -525,18 +555,7 @@
 }
 
 void SurfaceFlinger::deleteTextureAsync(uint32_t texture) {
-    class MessageDestroyGLTexture : public MessageBase {
-        RE::RenderEngine& engine;
-        uint32_t texture;
-    public:
-        MessageDestroyGLTexture(RE::RenderEngine& engine, uint32_t texture)
-              : engine(engine), texture(texture) {}
-        virtual bool handler() {
-            engine.deleteTextures(1, &texture);
-            return true;
-        }
-    };
-    postMessageAsync(new MessageDestroyGLTexture(getRenderEngine(), texture));
+    postMessageAsync(new LambdaMessage([=] { getRenderEngine().deleteTextures(1, &texture); }));
 }
 
 class DispSyncSource final : public VSyncSource, private DispSync::Callback {
@@ -685,7 +704,7 @@
             std::make_unique<DispSyncSource>(&mPrimaryDispSync, SurfaceFlinger::vsyncPhaseOffsetNs,
                                              true, "app");
     mEventThread = std::make_unique<impl::EventThread>(mEventThreadSource.get(),
-                                                       [this]() { resyncWithRateLimit(); },
+                                                       [this] { resyncWithRateLimit(); },
                                                        impl::EventThread::InterceptVSyncsCallback(),
                                                        "appEventThread");
     mSfEventThreadSource =
@@ -694,7 +713,7 @@
 
     mSFEventThread =
             std::make_unique<impl::EventThread>(mSfEventThreadSource.get(),
-                                                [this]() { resyncWithRateLimit(); },
+                                                [this] { resyncWithRateLimit(); },
                                                 [this](nsecs_t timestamp) {
                                                     mInterceptor->saveVSyncEvent(timestamp);
                                                 },
@@ -717,31 +736,34 @@
     getBE().mHwc->registerCallback(this, getBE().mComposerSequenceId);
     // Process any initial hotplug and resulting display changes.
     processDisplayHotplugEventsLocked();
-    LOG_ALWAYS_FATAL_IF(!getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY),
-            "Registered composer callback but didn't create the default primary display");
+    const auto display = getDefaultDisplayDeviceLocked();
+    LOG_ALWAYS_FATAL_IF(!display, "Missing internal display after registering composer callback.");
+    LOG_ALWAYS_FATAL_IF(!getHwComposer().isConnected(display->getId()),
+                        "Internal display is disconnected.");
 
     // make the default display GLContext current so that we can create textures
     // when creating Layers (which may happens before we render something)
-    getDefaultDisplayDeviceLocked()->makeCurrent();
+    display->makeCurrent();
 
     if (useVrFlinger) {
-        auto vrFlingerRequestDisplayCallback = [this] (bool requestDisplay) {
+        auto vrFlingerRequestDisplayCallback = [this](bool requestDisplay) {
             // This callback is called from the vr flinger dispatch thread. We
             // need to call signalTransaction(), which requires holding
             // mStateLock when we're not on the main thread. Acquiring
             // mStateLock from the vr flinger dispatch thread might trigger a
             // deadlock in surface flinger (see b/66916578), so post a message
             // to be handled on the main thread instead.
-            sp<LambdaMessage> message = new LambdaMessage([=]() {
+            postMessageAsync(new LambdaMessage([=] {
                 ALOGI("VR request display mode: requestDisplay=%d", requestDisplay);
                 mVrFlingerRequestsDisplay = requestDisplay;
                 signalTransaction();
-            });
-            postMessageAsync(message);
+            }));
         };
-        mVrFlinger = dvr::VrFlinger::Create(getBE().mHwc->getComposer(),
-                getBE().mHwc->getHwcDisplayId(HWC_DISPLAY_PRIMARY).value_or(0),
-                vrFlingerRequestDisplayCallback);
+        mVrFlinger = dvr::VrFlinger::Create(getHwComposer().getComposer(),
+                                            getHwComposer()
+                                                    .getHwcDisplayId(display->getId())
+                                                    .value_or(0),
+                                            vrFlingerRequestDisplayCallback);
         if (!mVrFlinger) {
             ALOGE("Failed to start vrflinger");
         }
@@ -776,7 +798,7 @@
     // and apply this saturation matrix on Display P3 content. Unless the risk of applying
     // such saturation matrix on Display P3 is understood fully, the API should always return
     // identify matrix.
-    mEnhancedSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(HWC_DISPLAY_PRIMARY,
+    mEnhancedSaturationMatrix = getBE().mHwc->getDataspaceSaturationMatrix(display->getId(),
             Dataspace::SRGB_LINEAR);
 
     // we will apply this on Display P3.
@@ -858,18 +880,15 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& display,
-        Vector<DisplayInfo>* configs) {
-    if (configs == nullptr || display.get() == nullptr) {
+status_t SurfaceFlinger::getDisplayConfigs(const sp<IBinder>& displayToken,
+                                           Vector<DisplayInfo>* configs) {
+    if (!displayToken || !configs) {
         return BAD_VALUE;
     }
 
-    if (!display.get())
-        return NAME_NOT_FOUND;
-
     int32_t type = NAME_NOT_FOUND;
-    for (int i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
-        if (display == mBuiltinDisplays[i]) {
+    for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
+        if (displayToken == mDisplayTokens[i]) {
             type = i;
             break;
         }
@@ -923,8 +942,8 @@
             info.density = density;
 
             // TODO: this needs to go away (currently needed only by webkit)
-            sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
-            info.orientation = hw ? hw->getOrientation() : 0;
+            const auto display = getDefaultDisplayDeviceLocked();
+            info.orientation = display ? display->getOrientation() : 0;
         } else {
             // TODO: where should this value come from?
             static const int TV_DENSITY = 213;
@@ -968,9 +987,8 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>& /* display */,
-        DisplayStatInfo* stats) {
-    if (stats == nullptr) {
+status_t SurfaceFlinger::getDisplayStats(const sp<IBinder>&, DisplayStatInfo* stats) {
+    if (!stats) {
         return BAD_VALUE;
     }
 
@@ -981,87 +999,62 @@
     return NO_ERROR;
 }
 
-int SurfaceFlinger::getActiveConfig(const sp<IBinder>& display) {
-    if (display == nullptr) {
-        ALOGE("%s : display is nullptr", __func__);
+int SurfaceFlinger::getActiveConfig(const sp<IBinder>& displayToken) {
+    const auto display = getDisplayDevice(displayToken);
+    if (!display) {
+        ALOGE("getActiveConfig: Invalid display token %p", displayToken.get());
         return BAD_VALUE;
     }
 
-    sp<const DisplayDevice> device(getDisplayDevice(display));
-    if (device != nullptr) {
-        return device->getActiveConfig();
-    }
-
-    return BAD_VALUE;
+    return display->getActiveConfig();
 }
 
-void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode) {
-    ALOGD("Set active config mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
-          this);
-    int32_t type = hw->getDisplayType();
-    int currentMode = hw->getActiveConfig();
-
+void SurfaceFlinger::setActiveConfigInternal(const sp<DisplayDevice>& display, int mode) {
+    int currentMode = display->getActiveConfig();
     if (mode == currentMode) {
-        ALOGD("Screen type=%d is already mode=%d", hw->getDisplayType(), mode);
         return;
     }
 
-    if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
+    if (display->isVirtual()) {
         ALOGW("Trying to set config for virtual display");
         return;
     }
 
-    hw->setActiveConfig(mode);
-    getHwComposer().setActiveConfig(type, mode);
+    display->setActiveConfig(mode);
+    getHwComposer().setActiveConfig(display->getDisplayType(), mode);
 }
 
-status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& display, int mode) {
-    class MessageSetActiveConfig: public MessageBase {
-        SurfaceFlinger& mFlinger;
-        sp<IBinder> mDisplay;
-        int mMode;
-    public:
-        MessageSetActiveConfig(SurfaceFlinger& flinger, const sp<IBinder>& disp,
-                               int mode) :
-            mFlinger(flinger), mDisplay(disp) { mMode = mode; }
-        virtual bool handler() {
-            Vector<DisplayInfo> configs;
-            mFlinger.getDisplayConfigs(mDisplay, &configs);
-            if (mMode < 0 || mMode >= static_cast<int>(configs.size())) {
-                ALOGE("Attempt to set active config = %d for display with %zu configs",
-                        mMode, configs.size());
-                return true;
-            }
-            sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
-            if (hw == nullptr) {
-                ALOGE("Attempt to set active config = %d for null display %p",
-                        mMode, mDisplay.get());
-            } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
-                ALOGW("Attempt to set active config = %d for virtual display",
-                        mMode);
-            } else {
-                mFlinger.setActiveConfigInternal(hw, mMode);
-            }
-            return true;
+status_t SurfaceFlinger::setActiveConfig(const sp<IBinder>& displayToken, int mode) {
+    postMessageSync(new LambdaMessage([&] {
+        Vector<DisplayInfo> configs;
+        getDisplayConfigs(displayToken, &configs);
+        if (mode < 0 || mode >= static_cast<int>(configs.size())) {
+            ALOGE("Attempt to set active config %d for display with %zu configs", mode,
+                  configs.size());
+            return;
         }
-    };
-    sp<MessageBase> msg = new MessageSetActiveConfig(*this, display, mode);
-    postMessageSync(msg);
+        const auto display = getDisplayDevice(displayToken);
+        if (!display) {
+            ALOGE("Attempt to set active config %d for invalid display token %p", mode,
+                  displayToken.get());
+        } else if (display->isVirtual()) {
+            ALOGW("Attempt to set active config %d for virtual display", mode);
+        } else {
+            setActiveConfigInternal(display, mode);
+        }
+    }));
+
     return NO_ERROR;
 }
-status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& display,
-        Vector<ColorMode>* outColorModes) {
-    if ((outColorModes == nullptr) || (display.get() == nullptr)) {
+status_t SurfaceFlinger::getDisplayColorModes(const sp<IBinder>& displayToken,
+                                              Vector<ColorMode>* outColorModes) {
+    if (!displayToken || !outColorModes) {
         return BAD_VALUE;
     }
 
-    if (!display.get()) {
-        return NAME_NOT_FOUND;
-    }
-
     int32_t type = NAME_NOT_FOUND;
-    for (int i=0 ; i<DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES ; i++) {
-        if (display == mBuiltinDisplays[i]) {
+    for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
+        if (displayToken == mDisplayTokens[i]) {
             type = i;
             break;
         }
@@ -1083,79 +1076,62 @@
     return NO_ERROR;
 }
 
-ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& display) {
-    sp<const DisplayDevice> device(getDisplayDevice(display));
-    if (device != nullptr) {
-        return device->getActiveColorMode();
+ColorMode SurfaceFlinger::getActiveColorMode(const sp<IBinder>& displayToken) {
+    if (const auto display = getDisplayDevice(displayToken)) {
+        return display->getActiveColorMode();
     }
     return static_cast<ColorMode>(BAD_VALUE);
 }
 
-void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& hw,
-                                                ColorMode mode, Dataspace dataSpace,
-                                                RenderIntent renderIntent) {
-    int32_t type = hw->getDisplayType();
-    ColorMode currentMode = hw->getActiveColorMode();
-    Dataspace currentDataSpace = hw->getCompositionDataSpace();
-    RenderIntent currentRenderIntent = hw->getActiveRenderIntent();
+void SurfaceFlinger::setActiveColorModeInternal(const sp<DisplayDevice>& display, ColorMode mode,
+                                                Dataspace dataSpace, RenderIntent renderIntent) {
+    ColorMode currentMode = display->getActiveColorMode();
+    Dataspace currentDataSpace = display->getCompositionDataSpace();
+    RenderIntent currentRenderIntent = display->getActiveRenderIntent();
 
     if (mode == currentMode && dataSpace == currentDataSpace &&
         renderIntent == currentRenderIntent) {
         return;
     }
 
-    if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
+    if (display->isVirtual()) {
         ALOGW("Trying to set config for virtual display");
         return;
     }
 
-    hw->setActiveColorMode(mode);
-    hw->setCompositionDataSpace(dataSpace);
-    hw->setActiveRenderIntent(renderIntent);
-    getHwComposer().setActiveColorMode(type, mode, renderIntent);
+    display->setActiveColorMode(mode);
+    display->setCompositionDataSpace(dataSpace);
+    display->setActiveRenderIntent(renderIntent);
+    getHwComposer().setActiveColorMode(display->getDisplayType(), mode, renderIntent);
 
     ALOGV("Set active color mode: %s (%d), active render intent: %s (%d), type=%d",
-          decodeColorMode(mode).c_str(), mode,
-          decodeRenderIntent(renderIntent).c_str(), renderIntent,
-          hw->getDisplayType());
+          decodeColorMode(mode).c_str(), mode, decodeRenderIntent(renderIntent).c_str(),
+          renderIntent, display->getDisplayType());
 }
 
-
-status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& display,
-        ColorMode colorMode) {
-    class MessageSetActiveColorMode: public MessageBase {
-        SurfaceFlinger& mFlinger;
-        sp<IBinder> mDisplay;
-        ColorMode mMode;
-    public:
-        MessageSetActiveColorMode(SurfaceFlinger& flinger, const sp<IBinder>& disp,
-                               ColorMode mode) :
-            mFlinger(flinger), mDisplay(disp) { mMode = mode; }
-        virtual bool handler() {
-            Vector<ColorMode> modes;
-            mFlinger.getDisplayColorModes(mDisplay, &modes);
-            bool exists = std::find(std::begin(modes), std::end(modes), mMode) != std::end(modes);
-            if (mMode < ColorMode::NATIVE || !exists) {
-                ALOGE("Attempt to set invalid active color mode %s (%d) for display %p",
-                      decodeColorMode(mMode).c_str(), mMode, mDisplay.get());
-                return true;
-            }
-            sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
-            if (hw == nullptr) {
-                ALOGE("Attempt to set active color mode %s (%d) for null display %p",
-                      decodeColorMode(mMode).c_str(), mMode, mDisplay.get());
-            } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
-                ALOGW("Attempt to set active color mode %s %d for virtual display",
-                      decodeColorMode(mMode).c_str(), mMode);
-            } else {
-                mFlinger.setActiveColorModeInternal(hw, mMode, Dataspace::UNKNOWN,
-                                                    RenderIntent::COLORIMETRIC);
-            }
-            return true;
+status_t SurfaceFlinger::setActiveColorMode(const sp<IBinder>& displayToken, ColorMode mode) {
+    postMessageSync(new LambdaMessage([&] {
+        Vector<ColorMode> modes;
+        getDisplayColorModes(displayToken, &modes);
+        bool exists = std::find(std::begin(modes), std::end(modes), mode) != std::end(modes);
+        if (mode < ColorMode::NATIVE || !exists) {
+            ALOGE("Attempt to set invalid active color mode %s (%d) for display token %p",
+                  decodeColorMode(mode).c_str(), mode, displayToken.get());
+            return;
         }
-    };
-    sp<MessageBase> msg = new MessageSetActiveColorMode(*this, display, colorMode);
-    postMessageSync(msg);
+        const auto display = getDisplayDevice(displayToken);
+        if (!display) {
+            ALOGE("Attempt to set active color mode %s (%d) for invalid display token %p",
+                  decodeColorMode(mode).c_str(), mode, displayToken.get());
+        } else if (display->isVirtual()) {
+            ALOGW("Attempt to set active color mode %s (%d) for virtual display",
+                  decodeColorMode(mode).c_str(), mode);
+        } else {
+            setActiveColorModeInternal(display, mode, Dataspace::UNKNOWN,
+                                       RenderIntent::COLORIMETRIC);
+        }
+    }));
+
     return NO_ERROR;
 }
 
@@ -1171,20 +1147,20 @@
     return NO_ERROR;
 }
 
-status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& display,
-        HdrCapabilities* outCapabilities) const {
+status_t SurfaceFlinger::getHdrCapabilities(const sp<IBinder>& displayToken,
+                                            HdrCapabilities* outCapabilities) const {
     Mutex::Autolock _l(mStateLock);
 
-    sp<const DisplayDevice> displayDevice(getDisplayDeviceLocked(display));
-    if (displayDevice == nullptr) {
-        ALOGE("getHdrCapabilities: Invalid display %p", displayDevice.get());
+    const auto display = getDisplayDeviceLocked(displayToken);
+    if (!display) {
+        ALOGE("getHdrCapabilities: Invalid display token %p", displayToken.get());
         return BAD_VALUE;
     }
 
     // At this point the DisplayDeivce should already be set up,
     // meaning the luminance information is already queried from
     // hardware composer and stored properly.
-    const HdrCapabilities& capabilities = displayDevice->getHdrCapabilities();
+    const HdrCapabilities& capabilities = display->getHdrCapabilities();
     *outCapabilities = HdrCapabilities(capabilities.getSupportedHdrTypes(),
                                        capabilities.getDesiredMaxLuminance(),
                                        capabilities.getDesiredMaxAverageLuminance(),
@@ -1194,7 +1170,7 @@
 }
 
 status_t SurfaceFlinger::enableVSyncInjections(bool enable) {
-    sp<LambdaMessage> enableVSyncInjections = new LambdaMessage([&]() {
+    postMessageSync(new LambdaMessage([&] {
         Mutex::Autolock _l(mStateLock);
 
         if (mInjectVSyncs == enable) {
@@ -1206,8 +1182,7 @@
             if (mVSyncInjector.get() == nullptr) {
                 mVSyncInjector = std::make_unique<InjectVSyncSource>();
                 mInjectorEventThread = std::make_unique<
-                        impl::EventThread>(mVSyncInjector.get(),
-                                           [this]() { resyncWithRateLimit(); },
+                        impl::EventThread>(mVSyncInjector.get(), [this] { resyncWithRateLimit(); },
                                            impl::EventThread::InterceptVSyncsCallback(),
                                            "injEventThread");
             }
@@ -1218,8 +1193,8 @@
         }
 
         mInjectVSyncs = enable;
-    });
-    postMessageSync(enableVSyncInjections);
+    }));
+
     return NO_ERROR;
 }
 
@@ -1319,7 +1294,6 @@
     Mutex::Autolock _l(mHWVsyncLock);
     if (!mPrimaryHWVsyncEnabled && mHWVsyncAvailable) {
         mPrimaryDispSync.beginResync();
-        //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
         mEventControlThread->setVsyncEnabled(true);
         mPrimaryHWVsyncEnabled = true;
     }
@@ -1336,7 +1310,12 @@
         return;
     }
 
-    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
+    if (!getHwComposer().isConnected(displayId)) {
+        return;
+    }
+
+    const auto activeConfig = getHwComposer().getActiveConfig(displayId);
     const nsecs_t period = activeConfig->getVsyncPeriod();
 
     mPrimaryDispSync.reset();
@@ -1344,7 +1323,6 @@
 
     if (!mPrimaryHWVsyncEnabled) {
         mPrimaryDispSync.beginResync();
-        //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, true);
         mEventControlThread->setVsyncEnabled(true);
         mPrimaryHWVsyncEnabled = true;
     }
@@ -1353,7 +1331,6 @@
 void SurfaceFlinger::disableHardwareVsync(bool makeUnavailable) {
     Mutex::Autolock _l(mHWVsyncLock);
     if (mPrimaryHWVsyncEnabled) {
-        //eventControl(HWC_DISPLAY_PRIMARY, SurfaceFlinger::EVENT_VSYNC, false);
         mEventControlThread->setVsyncEnabled(false);
         mPrimaryDispSync.endResync();
         mPrimaryHWVsyncEnabled = false;
@@ -1375,8 +1352,10 @@
     sLastResyncAttempted = now;
 }
 
-void SurfaceFlinger::onVsyncReceived(int32_t sequenceId,
-        hwc2_display_t displayId, int64_t timestamp) {
+void SurfaceFlinger::onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
+                                     int64_t timestamp) {
+    ATRACE_NAME("SF onVsync");
+
     Mutex::Autolock lock(mStateLock);
     // Ignore any vsyncs from a previous hardware composer.
     if (sequenceId != getBE().mComposerSequenceId) {
@@ -1384,7 +1363,12 @@
     }
 
     int32_t type;
-    if (!getBE().mHwc->onVsync(displayId, timestamp, &type)) {
+    if (!getBE().mHwc->onVsync(hwcDisplayId, timestamp, &type)) {
+        return;
+    }
+
+    if (type != DisplayDevice::DISPLAY_PRIMARY) {
+        // For now, we don't do anything with external display vsyncs.
         return;
     }
 
@@ -1392,7 +1376,7 @@
 
     { // Scope for the lock
         Mutex::Autolock _l(mHWVsyncLock);
-        if (type == DisplayDevice::DISPLAY_PRIMARY && mPrimaryHWVsyncEnabled) {
+        if (mPrimaryHWVsyncEnabled) {
             needsHwVsync = mPrimaryDispSync.addResyncSample(timestamp);
         }
     }
@@ -1409,9 +1393,9 @@
     *compositorTiming = getBE().mCompositorTiming;
 }
 
-void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+void SurfaceFlinger::onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
                                        HWC2::Connection connection) {
-    ALOGV("onHotplugReceived(%d, %" PRIu64 ", %s)", sequenceId, display,
+    ALOGV("%s(%d, %" PRIu64 ", %s)", __FUNCTION__, sequenceId, hwcDisplayId,
           connection == HWC2::Connection::Connected ? "connected" : "disconnected");
 
     // Ignore events that do not have the right sequenceId.
@@ -1425,7 +1409,7 @@
     // acquire it here.
     ConditionalLock lock(mStateLock, std::this_thread::get_id() != mMainThreadId);
 
-    mPendingHotplugEvents.emplace_back(HotplugEvent{display, connection});
+    mPendingHotplugEvents.emplace_back(HotplugEvent{hwcDisplayId, connection});
 
     if (std::this_thread::get_id() == mMainThreadId) {
         // Process all pending hot plug events immediately if we are on the main thread.
@@ -1435,8 +1419,7 @@
     setTransactionFlags(eDisplayTransactionNeeded);
 }
 
-void SurfaceFlinger::onRefreshReceived(int sequenceId,
-                                       hwc2_display_t /*display*/) {
+void SurfaceFlinger::onRefreshReceived(int sequenceId, hwc2_display_t /*hwcDisplayId*/) {
     Mutex::Autolock lock(mStateLock);
     if (sequenceId != getBE().mComposerSequenceId) {
         return;
@@ -1481,8 +1464,13 @@
 
     Mutex::Autolock _l(mStateLock);
 
-    int currentDisplayPowerMode = getDisplayDeviceLocked(
-            mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY])->getPowerMode();
+    sp<DisplayDevice> display = getDefaultDisplayDeviceLocked();
+    LOG_ALWAYS_FATAL_IF(!display);
+    const int currentDisplayPowerMode = display->getPowerMode();
+    // This DisplayDevice will no longer be relevant once resetDisplayState() is
+    // called below. Clear the reference now so we don't accidentally use it
+    // later.
+    display.clear();
 
     if (!vrFlingerRequestsDisplay) {
         mVrFlinger->SeizeDisplayOwnership();
@@ -1499,27 +1487,32 @@
 
     if (vrFlingerRequestsDisplay) {
         mVrFlinger->GrantDisplayOwnership();
-    } else {
-        enableHardwareVsync();
     }
 
     mVisibleRegionsDirty = true;
     invalidateHwcGeometry();
 
     // Re-enable default display.
-    sp<DisplayDevice> hw(getDisplayDeviceLocked(
-            mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]));
-    setPowerModeInternal(hw, currentDisplayPowerMode, /*stateLockHeld*/ true);
+    display = getDefaultDisplayDeviceLocked();
+    LOG_ALWAYS_FATAL_IF(!display);
+    setPowerModeInternal(display, currentDisplayPowerMode, /*stateLockHeld*/ true);
 
     // Reset the timing values to account for the period of the swapped in HWC
-    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
     const nsecs_t period = activeConfig->getVsyncPeriod();
     mAnimFrameTracker.setDisplayRefreshPeriod(period);
 
+    // The present fences returned from vr_hwc are not an accurate
+    // representation of vsync times.
+    mPrimaryDispSync.setIgnorePresentFences(
+            getBE().mHwc->isUsingVrComposer() || !hasSyncFramework);
+
     // Use phase of 0 since phase is not known.
     // Use latency of 0, which will snap to the ideal latency.
     setCompositorTimingSnapped(0, period, 0);
 
+    resyncToHardwareVsync(false);
+
     android_atomic_or(1, &mRepaintEverything);
     setTransactionFlags(eDisplayTransactionNeeded);
 }
@@ -1532,6 +1525,7 @@
                     mPreviousPresentFence != Fence::NO_FENCE &&
                     (mPreviousPresentFence->getSignalTime() ==
                             Fence::SIGNAL_TIME_PENDING);
+            mFrameMissedCount += frameMissed;
             ATRACE_INT("FrameMissed", static_cast<int>(frameMissed));
             if (frameMissed) {
                 mTimeStats.incrementMissedFrames();
@@ -1594,13 +1588,10 @@
     doComposition();
     postComposition(refreshStartTime);
 
-    mPreviousPresentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
-
     mHadClientComposition = false;
-    for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
-        const sp<DisplayDevice>& displayDevice = mDisplays[displayId];
+    for (const auto& [token, display] : mDisplays) {
         mHadClientComposition = mHadClientComposition ||
-                getBE().mHwc->hasClientComposition(displayDevice->getHwcDisplayId());
+                getBE().mHwc->hasClientComposition(display->getId());
     }
     mVsyncModulator.onRefreshed(mHadClientComposition);
 
@@ -1614,21 +1605,20 @@
         return;
 
     const bool repaintEverything = mRepaintEverything;
-    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-        const sp<DisplayDevice>& hw(mDisplays[dpy]);
-        if (hw->isDisplayOn()) {
+    for (const auto& [token, display] : mDisplays) {
+        if (display->isPoweredOn()) {
             // transform the dirty region into this screen's coordinate space
-            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
+            const Region dirtyRegion = display->getDirtyRegion(repaintEverything);
             if (!dirtyRegion.isEmpty()) {
                 // redraw the whole screen
-                doComposeSurfaces(hw);
+                doComposeSurfaces(display);
 
                 // and draw the dirty region
-                const int32_t height = hw->getHeight();
+                const int32_t height = display->getHeight();
                 auto& engine(getRenderEngine());
                 engine.fillRegionWithColor(dirtyRegion, height, 1, 0, 1, 1);
 
-                hw->swapBuffers(getHwComposer());
+                display->swapBuffers(getHwComposer());
             }
         }
     }
@@ -1639,17 +1629,14 @@
         usleep(mDebugRegion * 1000);
     }
 
-    for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
-        auto& displayDevice = mDisplays[displayId];
-        if (!displayDevice->isDisplayOn()) {
+    for (const auto& [token, display] : mDisplays) {
+        if (!display->isPoweredOn()) {
             continue;
         }
 
-        status_t result = displayDevice->prepareFrame(*getBE().mHwc);
-        ALOGE_IF(result != NO_ERROR,
-                 "prepareFrame for display %zd failed:"
-                 " %d (%s)",
-                 displayId, result, strerror(-result));
+        status_t result = display->prepareFrame(*getBE().mHwc);
+        ALOGE_IF(result != NO_ERROR, "prepareFrame for display %d failed: %d (%s)",
+                 display->getId(), result, strerror(-result));
     }
 }
 
@@ -1664,19 +1651,14 @@
 void SurfaceFlinger::logLayerStats() {
     ATRACE_CALL();
     if (CC_UNLIKELY(mLayerStats.isEnabled())) {
-        int32_t hwcId = -1;
-        for (size_t dpy = 0; dpy < mDisplays.size(); ++dpy) {
-            const sp<const DisplayDevice>& displayDevice(mDisplays[dpy]);
-            if (displayDevice->isPrimary()) {
-                hwcId = displayDevice->getHwcDisplayId();
-                break;
+        for (const auto& [token, display] : mDisplays) {
+            if (display->isPrimary()) {
+                mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(*display));
+                return;
             }
         }
-        if (hwcId < 0) {
-            ALOGE("LayerStats: Hmmm, no primary display?");
-            return;
-        }
-        mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(hwcId));
+
+        ALOGE("logLayerStats: no primary display");
     }
 }
 
@@ -1768,21 +1750,22 @@
     }
 
     // |mStateLock| not needed as we are on the main thread
-    const sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
+    const auto display = getDefaultDisplayDeviceLocked();
 
     getBE().mGlCompositionDoneTimeline.updateSignalTimes();
     std::shared_ptr<FenceTime> glCompositionDoneFenceTime;
-    if (hw && getBE().mHwc->hasClientComposition(HWC_DISPLAY_PRIMARY)) {
+    if (display && getHwComposer().hasClientComposition(display->getId())) {
         glCompositionDoneFenceTime =
-                std::make_shared<FenceTime>(hw->getClientTargetAcquireFence());
+                std::make_shared<FenceTime>(display->getClientTargetAcquireFence());
         getBE().mGlCompositionDoneTimeline.push(glCompositionDoneFenceTime);
     } else {
         glCompositionDoneFenceTime = FenceTime::NO_FENCE;
     }
 
     getBE().mDisplayTimeline.updateSignalTimes();
-    sp<Fence> presentFence = getBE().mHwc->getPresentFence(HWC_DISPLAY_PRIMARY);
-    auto presentFenceTime = std::make_shared<FenceTime>(presentFence);
+    mPreviousPresentFence =
+            display ? getHwComposer().getPresentFence(display->getId()) : Fence::NO_FENCE;
+    auto presentFenceTime = std::make_shared<FenceTime>(mPreviousPresentFence);
     getBE().mDisplayTimeline.push(presentFenceTime);
 
     nsecs_t vsyncPhase = mPrimaryDispSync.computeNextRefresh(0);
@@ -1817,7 +1800,7 @@
     }
 
     if (!hasSyncFramework) {
-        if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY) && hw->isDisplayOn()) {
+        if (display && getHwComposer().isConnected(display->getId()) && display->isPoweredOn()) {
             enableHardwareVsync();
         }
     }
@@ -1828,11 +1811,10 @@
         if (presentFenceTime->isValid()) {
             mAnimFrameTracker.setActualPresentFence(
                     std::move(presentFenceTime));
-        } else if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
+        } else if (display && getHwComposer().isConnected(display->getId())) {
             // The HWC doesn't support present fences, so use the refresh
             // timestamp instead.
-            nsecs_t presentTime =
-                    getBE().mHwc->getRefreshTimestamp(HWC_DISPLAY_PRIMARY);
+            const nsecs_t presentTime = getHwComposer().getRefreshTimestamp(display->getId());
             mAnimFrameTracker.setActualPresentTime(presentTime);
         }
         mAnimFrameTracker.advanceFrame();
@@ -1843,8 +1825,8 @@
         mTimeStats.incrementClientCompositionFrames();
     }
 
-    if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY) &&
-            hw->getPowerMode() == HWC_POWER_MODE_OFF) {
+    if (display && getHwComposer().isConnected(display->getId()) &&
+        display->getPowerMode() == HWC_POWER_MODE_OFF) {
         return;
     }
 
@@ -1885,21 +1867,20 @@
         mVisibleRegionsDirty = false;
         invalidateHwcGeometry();
 
-        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
+        for (const auto& pair : mDisplays) {
+            const auto& display = pair.second;
             Region opaqueRegion;
             Region dirtyRegion;
             Vector<sp<Layer>> layersSortedByZ;
             Vector<sp<Layer>> layersNeedingFences;
-            const sp<DisplayDevice>& displayDevice(mDisplays[dpy]);
-            const Transform& tr(displayDevice->getTransform());
-            const Rect bounds(displayDevice->getBounds());
-            if (displayDevice->isDisplayOn()) {
-                computeVisibleRegions(displayDevice, dirtyRegion, opaqueRegion);
+            const Transform& tr = display->getTransform();
+            const Rect bounds = display->getBounds();
+            if (display->isPoweredOn()) {
+                computeVisibleRegions(display, dirtyRegion, opaqueRegion);
 
                 mDrawingState.traverseInZOrder([&](Layer* layer) {
                     bool hwcLayerDestroyed = false;
-                    if (layer->belongsToDisplay(displayDevice->getLayerStack(),
-                                displayDevice->isPrimary())) {
+                    if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
                         Region drawRegion(tr.transform(
                                 layer->visibleNonTransparentRegion));
                         drawRegion.andSelf(bounds);
@@ -1908,15 +1889,13 @@
                         } else {
                             // Clear out the HWC layer if this layer was
                             // previously visible, but no longer is
-                            hwcLayerDestroyed = layer->destroyHwcLayer(
-                                    displayDevice->getHwcDisplayId());
+                            hwcLayerDestroyed = layer->destroyHwcLayer(display->getId());
                         }
                     } else {
-                        // WM changes displayDevice->layerStack upon sleep/awake.
+                        // WM changes display->layerStack upon sleep/awake.
                         // Here we make sure we delete the HWC layers even if
                         // WM changed their layer stack.
-                        hwcLayerDestroyed = layer->destroyHwcLayer(
-                                displayDevice->getHwcDisplayId());
+                        hwcLayerDestroyed = layer->destroyHwcLayer(display->getId());
                     }
 
                     // If a layer is not going to get a release fence because
@@ -1932,12 +1911,11 @@
                     }
                 });
             }
-            displayDevice->setVisibleLayersSortedByZ(layersSortedByZ);
-            displayDevice->setLayersNeedingFences(layersNeedingFences);
-            displayDevice->undefinedRegion.set(bounds);
-            displayDevice->undefinedRegion.subtractSelf(
-                    tr.transform(opaqueRegion));
-            displayDevice->dirtyRegion.orSelf(dirtyRegion);
+            display->setVisibleLayersSortedByZ(layersSortedByZ);
+            display->setLayersNeedingFences(layersNeedingFences);
+            display->undefinedRegion.set(bounds);
+            display->undefinedRegion.subtractSelf(tr.transform(opaqueRegion));
+            display->dirtyRegion.orSelf(dirtyRegion);
         }
     }
 }
@@ -1950,12 +1928,12 @@
 //  - Dataspace::UNKNOWN
 //  - Dataspace::BT2020_HLG
 //  - Dataspace::BT2020_PQ
-Dataspace SurfaceFlinger::getBestDataspace(
-    const sp<const DisplayDevice>& displayDevice, Dataspace* outHdrDataSpace) const {
+Dataspace SurfaceFlinger::getBestDataspace(const sp<const DisplayDevice>& display,
+                                           Dataspace* outHdrDataSpace) const {
     Dataspace bestDataSpace = Dataspace::SRGB;
     *outHdrDataSpace = Dataspace::UNKNOWN;
 
-    for (const auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+    for (const auto& layer : display->getVisibleLayersSortedByZ()) {
         switch (layer->getDataSpace()) {
             case Dataspace::V0_SCRGB:
             case Dataspace::V0_SCRGB_LINEAR:
@@ -1983,9 +1961,8 @@
 }
 
 // Pick the ColorMode / Dataspace for the display device.
-void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& displayDevice,
-                                   ColorMode* outMode, Dataspace* outDataSpace,
-                                   RenderIntent* outRenderIntent) const {
+void SurfaceFlinger::pickColorMode(const sp<DisplayDevice>& display, ColorMode* outMode,
+                                   Dataspace* outDataSpace, RenderIntent* outRenderIntent) const {
     if (mDisplayColorSetting == DisplayColorSetting::UNMANAGED) {
         *outMode = ColorMode::NATIVE;
         *outDataSpace = Dataspace::UNKNOWN;
@@ -1994,11 +1971,11 @@
     }
 
     Dataspace hdrDataSpace;
-    Dataspace bestDataSpace = getBestDataspace(displayDevice, &hdrDataSpace);
+    Dataspace bestDataSpace = getBestDataspace(display, &hdrDataSpace);
 
     // respect hdrDataSpace only when there is no legacy HDR support
     const bool isHdr = hdrDataSpace != Dataspace::UNKNOWN &&
-        !displayDevice->hasLegacyHdrSupport(hdrDataSpace);
+        !display->hasLegacyHdrSupport(hdrDataSpace);
     if (isHdr) {
         bestDataSpace = hdrDataSpace;
     }
@@ -2017,17 +1994,17 @@
             break;
     }
 
-    displayDevice->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
+    display->getBestColorMode(bestDataSpace, intent, outDataSpace, outMode, outRenderIntent);
 }
 
 void SurfaceFlinger::setUpHWComposer() {
     ATRACE_CALL();
     ALOGV("setUpHWComposer");
 
-    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-        bool dirty = !mDisplays[dpy]->getDirtyRegion(mRepaintEverything).isEmpty();
-        bool empty = mDisplays[dpy]->getVisibleLayersSortedByZ().size() == 0;
-        bool wasEmpty = !mDisplays[dpy]->lastCompositionHadVisibleLayers;
+    for (const auto& [token, display] : mDisplays) {
+        bool dirty = !display->getDirtyRegion(mRepaintEverything).isEmpty();
+        bool empty = display->getVisibleLayersSortedByZ().size() == 0;
+        bool wasEmpty = !display->lastCompositionHadVisibleLayers;
 
         // If nothing has changed (!dirty), don't recompose.
         // If something changed, but we don't currently have any visible layers,
@@ -2039,41 +2016,36 @@
         //   emit any black frames until a layer is added to the layer stack.
         bool mustRecompose = dirty && !(empty && wasEmpty);
 
-        ALOGV_IF(mDisplays[dpy]->getDisplayType() == DisplayDevice::DISPLAY_VIRTUAL,
-                "dpy[%zu]: %s composition (%sdirty %sempty %swasEmpty)", dpy,
-                mustRecompose ? "doing" : "skipping",
-                dirty ? "+" : "-",
-                empty ? "+" : "-",
-                wasEmpty ? "+" : "-");
+        ALOGV_IF(display->isVirtual(), "Display %d: %s composition (%sdirty %sempty %swasEmpty)",
+                 display->getId(), mustRecompose ? "doing" : "skipping", dirty ? "+" : "-",
+                 empty ? "+" : "-", wasEmpty ? "+" : "-");
 
-        mDisplays[dpy]->beginFrame(mustRecompose);
+        display->beginFrame(mustRecompose);
 
         if (mustRecompose) {
-            mDisplays[dpy]->lastCompositionHadVisibleLayers = !empty;
+            display->lastCompositionHadVisibleLayers = !empty;
         }
     }
 
     // build the h/w work list
     if (CC_UNLIKELY(mGeometryInvalid)) {
         mGeometryInvalid = false;
-        for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-            sp<const DisplayDevice> displayDevice(mDisplays[dpy]);
-            const auto hwcId = displayDevice->getHwcDisplayId();
-            if (hwcId >= 0) {
-                const Vector<sp<Layer>>& currentLayers(
-                        displayDevice->getVisibleLayersSortedByZ());
+        for (const auto& [token, display] : mDisplays) {
+            const auto displayId = display->getId();
+            if (displayId >= 0) {
+                const Vector<sp<Layer>>& currentLayers = display->getVisibleLayersSortedByZ();
                 for (size_t i = 0; i < currentLayers.size(); i++) {
                     const auto& layer = currentLayers[i];
-                    if (!layer->hasHwcLayer(hwcId)) {
-                        if (!layer->createHwcLayer(getBE().mHwc.get(), hwcId)) {
-                            layer->forceClientComposition(hwcId);
+                    if (!layer->hasHwcLayer(displayId)) {
+                        if (!layer->createHwcLayer(getBE().mHwc.get(), displayId)) {
+                            layer->forceClientComposition(displayId);
                             continue;
                         }
                     }
 
-                    layer->setGeometry(displayDevice, i);
+                    layer->setGeometry(display, i);
                     if (mDebugDisableHWC || mDebugRegion) {
-                        layer->forceClientComposition(hwcId);
+                        layer->forceClientComposition(displayId);
                     }
                 }
             }
@@ -2081,61 +2053,59 @@
     }
 
     // Set the per-frame data
-    for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
-        auto& displayDevice = mDisplays[displayId];
-        const auto hwcId = displayDevice->getHwcDisplayId();
-
-        if (hwcId < 0) {
+    for (const auto& [token, display] : mDisplays) {
+        const auto displayId = display->getId();
+        if (displayId < 0) {
             continue;
         }
+
         if (mDrawingState.colorMatrixChanged) {
-            displayDevice->setColorTransform(mDrawingState.colorMatrix);
-            status_t result = getBE().mHwc->setColorTransform(hwcId, mDrawingState.colorMatrix);
-            ALOGE_IF(result != NO_ERROR, "Failed to set color transform on "
-                    "display %zd: %d", displayId, result);
+            display->setColorTransform(mDrawingState.colorMatrix);
+            status_t result = getBE().mHwc->setColorTransform(displayId, mDrawingState.colorMatrix);
+            ALOGE_IF(result != NO_ERROR, "Failed to set color transform on display %d: %d",
+                     displayId, result);
         }
-        for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+        for (auto& layer : display->getVisibleLayersSortedByZ()) {
             if (layer->isHdrY410()) {
-                layer->forceClientComposition(hwcId);
+                layer->forceClientComposition(displayId);
             } else if ((layer->getDataSpace() == Dataspace::BT2020_PQ ||
                         layer->getDataSpace() == Dataspace::BT2020_ITU_PQ) &&
-                    !displayDevice->hasHDR10Support()) {
-                layer->forceClientComposition(hwcId);
+                    !display->hasHDR10Support()) {
+                layer->forceClientComposition(displayId);
             } else if ((layer->getDataSpace() == Dataspace::BT2020_HLG ||
                         layer->getDataSpace() == Dataspace::BT2020_ITU_HLG) &&
-                    !displayDevice->hasHLGSupport()) {
-                layer->forceClientComposition(hwcId);
+                    !display->hasHLGSupport()) {
+                layer->forceClientComposition(displayId);
             }
 
-            if (layer->getForceClientComposition(hwcId)) {
+            if (layer->getForceClientComposition(displayId)) {
                 ALOGV("[%s] Requesting Client composition", layer->getName().string());
-                layer->setCompositionType(hwcId, HWC2::Composition::Client);
+                layer->setCompositionType(displayId, HWC2::Composition::Client);
                 continue;
             }
 
-            layer->setPerFrameData(displayDevice);
+            layer->setPerFrameData(display);
         }
 
         if (hasWideColorDisplay) {
             ColorMode colorMode;
             Dataspace dataSpace;
             RenderIntent renderIntent;
-            pickColorMode(displayDevice, &colorMode, &dataSpace, &renderIntent);
-            setActiveColorModeInternal(displayDevice, colorMode, dataSpace, renderIntent);
+            pickColorMode(display, &colorMode, &dataSpace, &renderIntent);
+            setActiveColorModeInternal(display, colorMode, dataSpace, renderIntent);
         }
     }
 
     mDrawingState.colorMatrixChanged = false;
 
-    for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
-        auto& displayDevice = mDisplays[displayId];
-        if (!displayDevice->isDisplayOn()) {
+    for (const auto& [token, display] : mDisplays) {
+        if (!display->isPoweredOn()) {
             continue;
         }
 
-        status_t result = displayDevice->prepareFrame(*getBE().mHwc);
-        ALOGE_IF(result != NO_ERROR, "prepareFrame for display %zd failed:"
-                " %d (%s)", displayId, result, strerror(-result));
+        status_t result = display->prepareFrame(*getBE().mHwc);
+        ALOGE_IF(result != NO_ERROR, "prepareFrame for display %d failed: %d (%s)",
+                 display->getId(), result, strerror(-result));
     }
 }
 
@@ -2144,17 +2114,16 @@
     ALOGV("doComposition");
 
     const bool repaintEverything = android_atomic_and(0, &mRepaintEverything);
-    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-        const sp<DisplayDevice>& hw(mDisplays[dpy]);
-        if (hw->isDisplayOn()) {
+    for (const auto& [token, display] : mDisplays) {
+        if (display->isPoweredOn()) {
             // transform the dirty region into this screen's coordinate space
-            const Region dirtyRegion(hw->getDirtyRegion(repaintEverything));
+            const Region dirtyRegion = display->getDirtyRegion(repaintEverything);
 
             // repaint the framebuffer (if needed)
-            doDisplayComposition(hw, dirtyRegion);
+            doDisplayComposition(display, dirtyRegion);
 
-            hw->dirtyRegion.clear();
-            hw->flip();
+            display->dirtyRegion.clear();
+            display->flip();
         }
     }
     postFramebuffer();
@@ -2168,49 +2137,52 @@
     const nsecs_t now = systemTime();
     mDebugInSwapBuffers = now;
 
-    for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
-        auto& displayDevice = mDisplays[displayId];
-        if (!displayDevice->isDisplayOn()) {
+    for (const auto& [token, display] : mDisplays) {
+        if (!display->isPoweredOn()) {
             continue;
         }
-        const auto hwcId = displayDevice->getHwcDisplayId();
-        if (hwcId >= 0) {
-            getBE().mHwc->presentAndGetReleaseFences(hwcId);
+        const auto displayId = display->getId();
+        if (displayId >= 0) {
+            getBE().mHwc->presentAndGetReleaseFences(displayId);
         }
-        displayDevice->onSwapBuffersCompleted();
-        displayDevice->makeCurrent();
-        for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+        display->onSwapBuffersCompleted();
+        display->makeCurrent();
+        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 = layer->getHwcLayer(hwcId);
-            sp<Fence> releaseFence = getBE().mHwc->getLayerReleaseFence(hwcId, hwcLayer);
+            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
             // need to merge with the previous client target acquire fence.
             // 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 (layer->getCompositionType(hwcId) == HWC2::Composition::Client) {
+            if (layer->getCompositionType(displayId) == HWC2::Composition::Client) {
                 releaseFence = Fence::merge("LayerRelease", releaseFence,
-                        displayDevice->getClientTargetAcquireFence());
+                                            display->getClientTargetAcquireFence());
             }
 
-            layer->onLayerDisplayed(releaseFence);
+            layer->getBE().onLayerDisplayed(releaseFence);
         }
 
         // We've got a list of layers needing fences, that are disjoint with
-        // displayDevice->getVisibleLayersSortedByZ.  The best we can do is to
+        // display->getVisibleLayersSortedByZ.  The best we can do is to
         // supply them with the present fence.
-        if (!displayDevice->getLayersNeedingFences().isEmpty()) {
-            sp<Fence> presentFence = getBE().mHwc->getPresentFence(hwcId);
-            for (auto& layer : displayDevice->getLayersNeedingFences()) {
-                layer->onLayerDisplayed(presentFence);
+        if (!display->getLayersNeedingFences().isEmpty()) {
+            sp<Fence> presentFence = getBE().mHwc->getPresentFence(displayId);
+            for (auto& layer : display->getLayersNeedingFences()) {
+                layer->getBE().onLayerDisplayed(presentFence);
             }
         }
 
-        if (hwcId >= 0) {
-            getBE().mHwc->clearReleaseFences(hwcId);
+        if (displayId >= 0) {
+            getBE().mHwc->clearReleaseFences(displayId);
         }
     }
 
@@ -2218,8 +2190,9 @@
     mDebugInSwapBuffers = 0;
 
     // |mStateLock| not needed as we are on the main thread
-    if (getBE().mHwc->isConnected(HWC_DISPLAY_PRIMARY)) {
-        uint32_t flipCount = getDefaultDisplayDeviceLocked()->getPageFlipCount();
+    const auto display = getDefaultDisplayDeviceLocked();
+    if (display && getHwComposer().isConnected(display->getId())) {
+        const uint32_t flipCount = display->getPageFlipCount();
         if (flipCount % LOG_FRAME_STATS_PERIOD == 0) {
             logFrameStats();
         }
@@ -2256,7 +2229,7 @@
     // here the transaction has been committed
 }
 
-DisplayDevice::DisplayType SurfaceFlinger::determineDisplayType(hwc2_display_t display,
+DisplayDevice::DisplayType SurfaceFlinger::determineDisplayType(hwc2_display_t hwcDisplayId,
                                                                 HWC2::Connection connection) const {
     // Figure out whether the event is for the primary display or an
     // external display by matching the Hwc display id against one for a
@@ -2265,17 +2238,16 @@
     // have a connected primary display, we assume the new display is meant to
     // be the primary display, and then if we don't have an external display,
     // we assume it is that.
-    const auto primaryDisplayId =
-            getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_PRIMARY);
-    const auto externalDisplayId =
+    const auto primaryHwcDisplayId = getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_PRIMARY);
+    const auto externalHwcDisplayId =
             getBE().mHwc->getHwcDisplayId(DisplayDevice::DISPLAY_EXTERNAL);
-    if (primaryDisplayId && primaryDisplayId == display) {
+    if (primaryHwcDisplayId && primaryHwcDisplayId == hwcDisplayId) {
         return DisplayDevice::DISPLAY_PRIMARY;
-    } else if (externalDisplayId && externalDisplayId == display) {
-        return  DisplayDevice::DISPLAY_EXTERNAL;
-    } else if (connection == HWC2::Connection::Connected && !primaryDisplayId) {
+    } else if (externalHwcDisplayId && externalHwcDisplayId == hwcDisplayId) {
+        return DisplayDevice::DISPLAY_EXTERNAL;
+    } else if (connection == HWC2::Connection::Connected && !primaryHwcDisplayId) {
         return DisplayDevice::DISPLAY_PRIMARY;
-    } else if (connection == HWC2::Connection::Connected && !externalDisplayId) {
+    } else if (connection == HWC2::Connection::Connected && !externalHwcDisplayId) {
         return DisplayDevice::DISPLAY_EXTERNAL;
     }
 
@@ -2284,9 +2256,9 @@
 
 void SurfaceFlinger::processDisplayHotplugEventsLocked() {
     for (const auto& event : mPendingHotplugEvents) {
-        auto displayType = determineDisplayType(event.display, event.connection);
+        auto displayType = determineDisplayType(event.hwcDisplayId, event.connection);
         if (displayType == DisplayDevice::DISPLAY_ID_INVALID) {
-            ALOGW("Unable to determine the display type for display %" PRIu64, event.display);
+            ALOGW("Unable to determine the display type for display %" PRIu64, event.hwcDisplayId);
             continue;
         }
 
@@ -2295,29 +2267,34 @@
             continue;
         }
 
-        getBE().mHwc->onHotplug(event.display, displayType, event.connection);
+        const auto displayId =
+                getBE().mHwc->onHotplug(event.hwcDisplayId, displayType, event.connection);
+        if (displayId) {
+            ALOGV("Display %" PRIu64 " has stable ID %" PRIu64, event.hwcDisplayId, *displayId);
+        }
 
         if (event.connection == HWC2::Connection::Connected) {
-            if (!mBuiltinDisplays[displayType].get()) {
+            if (!mDisplayTokens[displayType].get()) {
                 ALOGV("Creating built in display %d", displayType);
-                mBuiltinDisplays[displayType] = new BBinder();
-                // All non-virtual displays are currently considered secure.
-                DisplayDeviceState info(displayType, true);
+                mDisplayTokens[displayType] = new BBinder();
+                DisplayDeviceState info;
+                info.type = displayType;
                 info.displayName = displayType == DisplayDevice::DISPLAY_PRIMARY ?
                         "Built-in Screen" : "External Screen";
-                mCurrentState.displays.add(mBuiltinDisplays[displayType], info);
+                info.isSecure = true; // All physical displays are currently considered secure.
+                mCurrentState.displays.add(mDisplayTokens[displayType], info);
                 mInterceptor->saveDisplayCreation(info);
             }
         } else {
             ALOGV("Removing built in display %d", displayType);
 
-            ssize_t idx = mCurrentState.displays.indexOfKey(mBuiltinDisplays[displayType]);
+            ssize_t idx = mCurrentState.displays.indexOfKey(mDisplayTokens[displayType]);
             if (idx >= 0) {
                 const DisplayDeviceState& info(mCurrentState.displays.valueAt(idx));
-                mInterceptor->saveDisplayDeletion(info.displayId);
+                mInterceptor->saveDisplayDeletion(info.sequenceId);
                 mCurrentState.displays.removeItemsAt(idx);
             }
-            mBuiltinDisplays[displayType].clear();
+            mDisplayTokens[displayType].clear();
         }
 
         processDisplayChangesLocked();
@@ -2327,32 +2304,28 @@
 }
 
 sp<DisplayDevice> SurfaceFlinger::setupNewDisplayDeviceInternal(
-        const wp<IBinder>& display, int hwcId, const DisplayDeviceState& state,
+        const wp<IBinder>& displayToken, int32_t displayId, const DisplayDeviceState& state,
         const sp<DisplaySurface>& dispSurface, const sp<IGraphicBufferProducer>& producer) {
     bool hasWideColorGamut = false;
     std::unordered_map<ColorMode, std::vector<RenderIntent>> hwcColorModes;
+    HdrCapabilities hdrCapabilities;
+    int32_t supportedPerFrameMetadata = 0;
 
-    if (hasWideColorDisplay) {
-        std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId);
+    if (hasWideColorDisplay && displayId >= 0) {
+        std::vector<ColorMode> modes = getHwComposer().getColorModes(displayId);
         for (ColorMode colorMode : modes) {
-            switch (colorMode) {
-                case ColorMode::DISPLAY_P3:
-                case ColorMode::ADOBE_RGB:
-                case ColorMode::DCI_P3:
-                    hasWideColorGamut = true;
-                    break;
-                default:
-                    break;
+            if (isWideColorMode(colorMode)) {
+                hasWideColorGamut = true;
             }
 
-            std::vector<RenderIntent> renderIntents = getHwComposer().getRenderIntents(hwcId,
-                                                                                       colorMode);
+            std::vector<RenderIntent> renderIntents =
+                    getHwComposer().getRenderIntents(displayId, colorMode);
             hwcColorModes.emplace(colorMode, renderIntents);
         }
-    }
 
-    HdrCapabilities hdrCapabilities;
-    getHwComposer().getHdrCapabilities(hwcId, &hdrCapabilities);
+        getHwComposer().getHdrCapabilities(displayId, &hdrCapabilities);
+        supportedPerFrameMetadata = getHwComposer().getSupportedPerFrameMetadata(displayId);
+    }
 
     auto nativeWindowSurface = mCreateNativeWindowSurface(producer);
     auto nativeWindow = nativeWindowSurface->getNativeWindow();
@@ -2362,7 +2335,7 @@
      */
     std::unique_ptr<RE::Surface> renderSurface = getRenderEngine().createSurface();
     renderSurface->setCritical(state.type == DisplayDevice::DISPLAY_PRIMARY);
-    renderSurface->setAsync(state.type >= DisplayDevice::DISPLAY_VIRTUAL);
+    renderSurface->setAsync(state.isVirtual());
     renderSurface->setNativeWindow(nativeWindow.get());
     const int displayWidth = renderSurface->queryWidth();
     const int displayHeight = renderSurface->queryHeight();
@@ -2374,20 +2347,18 @@
     // * In makeCurrent(), using eglSwapInterval. Some EGL drivers set the
     //   window's swap interval in eglMakeCurrent, so they'll override the
     //   interval we set here.
-    if (state.type >= DisplayDevice::DISPLAY_VIRTUAL) {
+    if (state.isVirtual()) {
         nativeWindow->setSwapInterval(nativeWindow.get(), 0);
     }
 
     // virtual displays are always considered enabled
-    auto initialPowerMode = (state.type >= DisplayDevice::DISPLAY_VIRTUAL) ? HWC_POWER_MODE_NORMAL
-                                                                           : HWC_POWER_MODE_OFF;
+    auto initialPowerMode = state.isVirtual() ? HWC_POWER_MODE_NORMAL : HWC_POWER_MODE_OFF;
 
-    sp<DisplayDevice> hw =
-            new DisplayDevice(this, state.type, hwcId, state.isSecure, display, nativeWindow,
-                              dispSurface, std::move(renderSurface), displayWidth, displayHeight,
-                              hasWideColorGamut, hdrCapabilities,
-                              getHwComposer().getSupportedPerFrameMetadata(hwcId),
-                              hwcColorModes, initialPowerMode);
+    sp<DisplayDevice> display =
+            new DisplayDevice(this, state.type, displayId, state.isSecure, displayToken,
+                              nativeWindow, dispSurface, std::move(renderSurface), displayWidth,
+                              displayHeight, hasWideColorGamut, hdrCapabilities,
+                              supportedPerFrameMetadata, hwcColorModes, initialPowerMode);
 
     if (maxFrameBufferAcquiredBuffers >= 3) {
         nativeWindowSurface->preallocateBuffers();
@@ -2399,16 +2370,16 @@
         defaultColorMode = ColorMode::SRGB;
         defaultDataSpace = Dataspace::SRGB;
     }
-    setActiveColorModeInternal(hw, defaultColorMode, defaultDataSpace,
+    setActiveColorModeInternal(display, defaultColorMode, defaultDataSpace,
                                RenderIntent::COLORIMETRIC);
     if (state.type < DisplayDevice::DISPLAY_VIRTUAL) {
-        hw->setActiveConfig(getHwComposer().getActiveConfigIndex(state.type));
+        display->setActiveConfig(getHwComposer().getActiveConfigIndex(state.type));
     }
-    hw->setLayerStack(state.layerStack);
-    hw->setProjection(state.orientation, state.viewport, state.frame);
-    hw->setDisplayName(state.displayName);
+    display->setLayerStack(state.layerStack);
+    display->setProjection(state.orientation, state.viewport, state.frame);
+    display->setDisplayName(state.displayName);
 
-    return hw;
+    return display;
 }
 
 void SurfaceFlinger::processDisplayChangesLocked() {
@@ -2433,17 +2404,22 @@
                 // Call makeCurrent() on the primary display so we can
                 // be sure that nothing associated with this display
                 // is current.
-                const sp<const DisplayDevice> defaultDisplay(getDefaultDisplayDeviceLocked());
-                if (defaultDisplay != nullptr) defaultDisplay->makeCurrent();
-                sp<DisplayDevice> hw(getDisplayDeviceLocked(draw.keyAt(i)));
-                if (hw != nullptr) hw->disconnect(getHwComposer());
-                if (draw[i].type < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES)
-                    mEventThread->onHotplugReceived(draw[i].type, false);
-                mDisplays.removeItem(draw.keyAt(i));
+                if (const auto defaultDisplay = getDefaultDisplayDeviceLocked()) {
+                    defaultDisplay->makeCurrent();
+                }
+                if (const auto display = getDisplayDeviceLocked(draw.keyAt(i))) {
+                    display->disconnect(getHwComposer());
+                }
+                if (draw[i].type == DisplayDevice::DISPLAY_PRIMARY) {
+                    mEventThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
+                } else if (draw[i].type == DisplayDevice::DISPLAY_EXTERNAL) {
+                    mEventThread->onHotplugReceived(EventThread::DisplayType::External, false);
+                }
+                mDisplays.erase(draw.keyAt(i));
             } else {
                 // this display is in both lists. see if something changed.
                 const DisplayDeviceState& state(curr[j]);
-                const wp<IBinder>& display(curr.keyAt(j));
+                const wp<IBinder>& displayToken = curr.keyAt(j);
                 const sp<IBinder> state_binder = IInterface::asBinder(state.surface);
                 const sp<IBinder> draw_binder = IInterface::asBinder(draw[i].surface);
                 if (state_binder != draw_binder) {
@@ -2451,26 +2427,26 @@
                     // recreating the DisplayDevice, so we just remove it
                     // from the drawing state, so that it get re-added
                     // below.
-                    sp<DisplayDevice> hw(getDisplayDeviceLocked(display));
-                    if (hw != nullptr) hw->disconnect(getHwComposer());
-                    mDisplays.removeItem(display);
+                    if (const auto display = getDisplayDeviceLocked(displayToken)) {
+                        display->disconnect(getHwComposer());
+                    }
+                    mDisplays.erase(displayToken);
                     mDrawingState.displays.removeItemsAt(i);
                     dc--;
                     // at this point we must loop to the next item
                     continue;
                 }
 
-                const sp<DisplayDevice> disp(getDisplayDeviceLocked(display));
-                if (disp != nullptr) {
+                if (const auto display = getDisplayDeviceLocked(displayToken)) {
                     if (state.layerStack != draw[i].layerStack) {
-                        disp->setLayerStack(state.layerStack);
+                        display->setLayerStack(state.layerStack);
                     }
                     if ((state.orientation != draw[i].orientation) ||
                         (state.viewport != draw[i].viewport) || (state.frame != draw[i].frame)) {
-                        disp->setProjection(state.orientation, state.viewport, state.frame);
+                        display->setProjection(state.orientation, state.viewport, state.frame);
                     }
                     if (state.width != draw[i].width || state.height != draw[i].height) {
-                        disp->setDisplaySize(state.width, state.height);
+                        display->setDisplaySize(state.width, state.height);
                     }
                 }
             }
@@ -2489,8 +2465,8 @@
                 sp<IGraphicBufferConsumer> bqConsumer;
                 mCreateBufferQueue(&bqProducer, &bqConsumer, false);
 
-                int32_t hwcId = -1;
-                if (state.isVirtualDisplay()) {
+                int32_t displayId = -1;
+                if (state.isVirtual()) {
                     // Virtual displays without a surface are dormant:
                     // they have external state (layer stack, projection,
                     // etc.) but no internal state (i.e. a DisplayDevice).
@@ -2508,13 +2484,14 @@
                             ALOGE_IF(status != NO_ERROR, "Unable to query format (%d)", status);
                             auto format = static_cast<ui::PixelFormat>(intFormat);
 
-                            getBE().mHwc->allocateVirtualDisplay(width, height, &format, &hwcId);
+                            getBE().mHwc->allocateVirtualDisplay(width, height, &format,
+                                                                 &displayId);
                         }
 
                         // TODO: Plumb requested format back up to consumer
 
                         sp<VirtualDisplaySurface> vds =
-                                new VirtualDisplaySurface(*getBE().mHwc, hwcId, state.surface,
+                                new VirtualDisplaySurface(*getBE().mHwc, displayId, state.surface,
                                                           bqProducer, bqConsumer,
                                                           state.displayName);
 
@@ -2527,18 +2504,24 @@
                              "surface is provided (%p), ignoring it",
                              state.surface.get());
 
-                    hwcId = state.type;
-                    dispSurface = new FramebufferSurface(*getBE().mHwc, hwcId, bqConsumer);
+                    displayId = state.type;
+                    dispSurface = new FramebufferSurface(*getBE().mHwc, displayId, bqConsumer);
                     producer = bqProducer;
                 }
 
-                const wp<IBinder>& display(curr.keyAt(i));
+                const wp<IBinder>& displayToken = curr.keyAt(i);
                 if (dispSurface != nullptr) {
-                    mDisplays.add(display,
-                                  setupNewDisplayDeviceInternal(display, hwcId, state, dispSurface,
-                                                                producer));
-                    if (!state.isVirtualDisplay()) {
-                        mEventThread->onHotplugReceived(state.type, true);
+                    mDisplays.emplace(displayToken,
+                                      setupNewDisplayDeviceInternal(displayToken, displayId, state,
+                                                                    dispSurface, producer));
+                    if (!state.isVirtual()) {
+                        if (state.type == DisplayDevice::DISPLAY_PRIMARY) {
+                            mEventThread->onHotplugReceived(EventThread::DisplayType::Primary,
+                                                            true);
+                        } else if (state.type == DisplayDevice::DISPLAY_EXTERNAL) {
+                            mEventThread->onHotplugReceived(EventThread::DisplayType::External,
+                                                            true);
+                        }
                     }
                 }
             }
@@ -2600,7 +2583,7 @@
         // happened yet, so we must use the current state layer list
         // (soon to become the drawing state list).
         //
-        sp<const DisplayDevice> disp;
+        sp<const DisplayDevice> hintDisplay;
         uint32_t currentlayerStack = 0;
         bool first = true;
         mCurrentState.traverseInZOrder([&](Layer* layer) {
@@ -2613,34 +2596,33 @@
                 // figure out if this layerstack is mirrored
                 // (more than one display) if so, pick the default display,
                 // if not, pick the only display it's on.
-                disp.clear();
-                for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-                    sp<const DisplayDevice> hw(mDisplays[dpy]);
-                    if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
-                        if (disp == nullptr) {
-                            disp = std::move(hw);
-                        } else {
-                            disp = nullptr;
+                hintDisplay = nullptr;
+                for (const auto& [token, display] : mDisplays) {
+                    if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
+                        if (hintDisplay) {
+                            hintDisplay = nullptr;
                             break;
+                        } else {
+                            hintDisplay = display;
                         }
                     }
                 }
             }
 
-            if (disp == nullptr) {
+            if (!hintDisplay) {
                 // NOTE: TEMPORARY FIX ONLY. Real fix should cause layers to
                 // redraw after transform hint changes. See bug 8508397.
 
                 // could be null when this layer is using a layerStack
                 // that is not visible on any display. Also can occur at
                 // screen off/on times.
-                disp = getDefaultDisplayDeviceLocked();
+                hintDisplay = getDefaultDisplayDeviceLocked();
             }
 
-            // disp can be null if there is no display available at all to get
+            // could be null if there is no display available at all to get
             // the transform hint from.
-            if (disp != nullptr) {
-                layer->updateTransformHint(disp);
+            if (hintDisplay) {
+                layer->updateTransformHint(hintDisplay);
             }
 
             first = false;
@@ -2683,14 +2665,13 @@
 
 void SurfaceFlinger::updateCursorAsync()
 {
-    for (size_t displayId = 0; displayId < mDisplays.size(); ++displayId) {
-        auto& displayDevice = mDisplays[displayId];
-        if (displayDevice->getHwcDisplayId() < 0) {
+    for (const auto& [token, display] : mDisplays) {
+        if (display->getId() < 0) {
             continue;
         }
 
-        for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
-            layer->updateCursorPosition(displayDevice);
+        for (auto& layer : display->getVisibleLayersSortedByZ()) {
+            layer->updateCursorPosition(display);
         }
     }
 }
@@ -2723,9 +2704,8 @@
     mTransactionCV.broadcast();
 }
 
-void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
-        Region& outDirtyRegion, Region& outOpaqueRegion)
-{
+void SurfaceFlinger::computeVisibleRegions(const sp<const DisplayDevice>& display,
+                                           Region& outDirtyRegion, Region& outOpaqueRegion) {
     ATRACE_CALL();
     ALOGV("computeVisibleRegions");
 
@@ -2740,8 +2720,9 @@
         const Layer::State& s(layer->getDrawingState());
 
         // only consider the layers on the given layer stack
-        if (!layer->belongsToDisplay(displayDevice->getLayerStack(), displayDevice->isPrimary()))
+        if (!layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
             return;
+        }
 
         /*
          * opaqueRegion: area of a surface that is fully opaque.
@@ -2861,10 +2842,9 @@
 }
 
 void SurfaceFlinger::invalidateLayerStack(const sp<const Layer>& layer, const Region& dirty) {
-    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-        const sp<DisplayDevice>& hw(mDisplays[dpy]);
-        if (layer->belongsToDisplay(hw->getLayerStack(), hw->isPrimary())) {
-            hw->dirtyRegion.orSelf(dirty);
+    for (const auto& [token, display] : mDisplays) {
+        if (layer->belongsToDisplay(display->getLayerStack(), display->isPrimary())) {
+            display->dirtyRegion.orSelf(dirty);
         }
     }
 }
@@ -2934,36 +2914,32 @@
     mGeometryInvalid = true;
 }
 
-
-void SurfaceFlinger::doDisplayComposition(
-        const sp<const DisplayDevice>& displayDevice,
-        const Region& inDirtyRegion)
-{
+void SurfaceFlinger::doDisplayComposition(const sp<const DisplayDevice>& display,
+                                          const Region& inDirtyRegion) {
     // We only need to actually compose the display if:
     // 1) It is being handled by hardware composer, which may need this to
     //    keep its virtual display state machine in sync, or
     // 2) There is work to be done (the dirty region isn't empty)
-    bool isHwcDisplay = displayDevice->getHwcDisplayId() >= 0;
+    bool isHwcDisplay = display->getId() >= 0;
     if (!isHwcDisplay && inDirtyRegion.isEmpty()) {
         ALOGV("Skipping display composition");
         return;
     }
 
     ALOGV("doDisplayComposition");
-    if (!doComposeSurfaces(displayDevice)) return;
+    if (!doComposeSurfaces(display)) return;
 
     // swap buffers (presentation)
-    displayDevice->swapBuffers(getHwComposer());
+    display->swapBuffers(getHwComposer());
 }
 
-bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& displayDevice)
-{
+bool SurfaceFlinger::doComposeSurfaces(const sp<const DisplayDevice>& display) {
     ALOGV("doComposeSurfaces");
 
-    const Region bounds(displayDevice->bounds());
-    const DisplayRenderArea renderArea(displayDevice);
-    const auto hwcId = displayDevice->getHwcDisplayId();
-    const bool hasClientComposition = getBE().mHwc->hasClientComposition(hwcId);
+    const Region bounds(display->bounds());
+    const DisplayRenderArea renderArea(display);
+    const auto displayId = display->getId();
+    const bool hasClientComposition = getBE().mHwc->hasClientComposition(displayId);
     ATRACE_INT("hasClientComposition", hasClientComposition);
 
     bool applyColorMatrix = false;
@@ -2973,14 +2949,14 @@
         ALOGV("hasClientComposition");
 
         Dataspace outputDataspace = Dataspace::UNKNOWN;
-        if (displayDevice->hasWideColorGamut()) {
-            outputDataspace = displayDevice->getCompositionDataSpace();
+        if (display->hasWideColorGamut()) {
+            outputDataspace = display->getCompositionDataSpace();
         }
         getBE().mRenderEngine->setOutputDataSpace(outputDataspace);
         getBE().mRenderEngine->setDisplayMaxLuminance(
-                displayDevice->getHdrCapabilities().getDesiredMaxLuminance());
+                display->getHdrCapabilities().getDesiredMaxLuminance());
 
-        const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(hwcId);
+        const bool hasDeviceComposition = getBE().mHwc->hasDeviceComposition(displayId);
         const bool skipClientColorTransform = getBE().mHwc->hasCapability(
             HWC2::Capability::SkipClientColorTransform);
 
@@ -2994,7 +2970,7 @@
         // thus we only apply this matrix when the render intent is not colorimetric
         // and the output color space is Display P3.
         needsEnhancedColorMatrix =
-            (displayDevice->getActiveRenderIntent() >= RenderIntent::ENHANCE &&
+            (display->getActiveRenderIntent() >= RenderIntent::ENHANCE &&
              outputDataspace == Dataspace::DISPLAY_P3);
         if (needsEnhancedColorMatrix) {
             colorMatrix *= mEnhancedSaturationMatrix;
@@ -3002,14 +2978,15 @@
 
         getRenderEngine().setupColorTransform(colorMatrix);
 
-        if (!displayDevice->makeCurrent()) {
+        if (!display->makeCurrent()) {
             ALOGW("DisplayDevice::makeCurrent failed. Aborting surface composition for display %s",
-                  displayDevice->getDisplayName().string());
+                  display->getDisplayName().c_str());
             getRenderEngine().resetCurrentSurface();
 
             // |mStateLock| not needed as we are on the main thread
-            if(!getDefaultDisplayDeviceLocked()->makeCurrent()) {
-              ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
+            const auto defaultDisplay = getDefaultDisplayDeviceLocked();
+            if (!defaultDisplay || !defaultDisplay->makeCurrent()) {
+                ALOGE("DisplayDevice::makeCurrent on default display failed. Aborting.");
             }
             return false;
         }
@@ -3026,31 +3003,31 @@
             // we start with the whole screen area and remove the scissor part
             // we're left with the letterbox region
             // (common case is that letterbox ends-up being empty)
-            const Region letterbox(bounds.subtract(displayDevice->getScissor()));
+            const Region letterbox = bounds.subtract(display->getScissor());
 
             // compute the area to clear
-            Region region(displayDevice->undefinedRegion.merge(letterbox));
+            const Region region = display->undefinedRegion.merge(letterbox);
 
             // screen is already cleared here
             if (!region.isEmpty()) {
                 // can happen with SurfaceView
-                drawWormhole(displayDevice, region);
+                drawWormhole(display, region);
             }
         }
 
-        if (displayDevice->getDisplayType() != DisplayDevice::DISPLAY_PRIMARY) {
+        if (!display->isPrimary()) {
             // just to be on the safe side, we don't set the
             // scissor on the main display. It should never be needed
             // anyways (though in theory it could since the API allows it).
-            const Rect& bounds(displayDevice->getBounds());
-            const Rect& scissor(displayDevice->getScissor());
+            const Rect& bounds = display->getBounds();
+            const Rect& scissor = display->getScissor();
             if (scissor != bounds) {
                 // scissor doesn't match the screen's dimensions, so we
                 // need to clear everything outside of it and enable
                 // the GL scissor so we don't draw anything where we shouldn't
 
                 // enable scissor for this frame
-                const uint32_t height = displayDevice->getHeight();
+                const uint32_t height = display->getHeight();
                 getBE().mRenderEngine->setScissor(scissor.left, height - scissor.bottom,
                         scissor.getWidth(), scissor.getHeight());
             }
@@ -3062,24 +3039,23 @@
      */
 
     ALOGV("Rendering client layers");
-    const Transform& displayTransform = displayDevice->getTransform();
+    const Transform& displayTransform = display->getTransform();
     bool firstLayer = true;
-    for (auto& layer : displayDevice->getVisibleLayersSortedByZ()) {
+    for (auto& layer : display->getVisibleLayersSortedByZ()) {
         const Region clip(bounds.intersect(
                 displayTransform.transform(layer->visibleRegion)));
         ALOGV("Layer: %s", layer->getName().string());
-        ALOGV("  Composition type: %s",
-                to_string(layer->getCompositionType(hwcId)).c_str());
+        ALOGV("  Composition type: %s", to_string(layer->getCompositionType(displayId)).c_str());
         if (!clip.isEmpty()) {
-            switch (layer->getCompositionType(hwcId)) {
+            switch (layer->getCompositionType(displayId)) {
                 case HWC2::Composition::Cursor:
                 case HWC2::Composition::Device:
                 case HWC2::Composition::Sideband:
                 case HWC2::Composition::SolidColor: {
                     const Layer::State& state(layer->getDrawingState());
-                    if (layer->getClearClientTarget(hwcId) && !firstLayer &&
-                            layer->isOpaque(state) && (state.color.a == 1.0f)
-                            && hasClientComposition) {
+                    if (layer->getClearClientTarget(displayId) && !firstLayer &&
+                        layer->isOpaque(state) && (layer->getAlpha() == 1.0f) &&
+                        hasClientComposition) {
                         // never clear the very first layer since we're
                         // guaranteed the FB is already cleared
                         layer->clearWithOpenGL(renderArea);
@@ -3108,8 +3084,9 @@
     return true;
 }
 
-void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& displayDevice, const Region& region) const {
-    const int32_t height = displayDevice->getHeight();
+void SurfaceFlinger::drawWormhole(const sp<const DisplayDevice>& display,
+                                  const Region& region) const {
+    const int32_t height = display->getHeight();
     auto& engine(getRenderEngine());
     engine.fillRegionWithColor(region, height, 0, 0, 0, 0);
 }
@@ -3340,53 +3317,51 @@
     }
 }
 
-uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s)
-{
-    ssize_t dpyIdx = mCurrentState.displays.indexOfKey(s.token);
-    if (dpyIdx < 0)
-        return 0;
+uint32_t SurfaceFlinger::setDisplayStateLocked(const DisplayState& s) {
+    const ssize_t index = mCurrentState.displays.indexOfKey(s.token);
+    if (index < 0) return 0;
 
     uint32_t flags = 0;
-    DisplayDeviceState& disp(mCurrentState.displays.editValueAt(dpyIdx));
-    if (disp.isValid()) {
-        const uint32_t what = s.what;
-        if (what & DisplayState::eSurfaceChanged) {
-            if (IInterface::asBinder(disp.surface) != IInterface::asBinder(s.surface)) {
-                disp.surface = s.surface;
-                flags |= eDisplayTransactionNeeded;
-            }
-        }
-        if (what & DisplayState::eLayerStackChanged) {
-            if (disp.layerStack != s.layerStack) {
-                disp.layerStack = s.layerStack;
-                flags |= eDisplayTransactionNeeded;
-            }
-        }
-        if (what & DisplayState::eDisplayProjectionChanged) {
-            if (disp.orientation != s.orientation) {
-                disp.orientation = s.orientation;
-                flags |= eDisplayTransactionNeeded;
-            }
-            if (disp.frame != s.frame) {
-                disp.frame = s.frame;
-                flags |= eDisplayTransactionNeeded;
-            }
-            if (disp.viewport != s.viewport) {
-                disp.viewport = s.viewport;
-                flags |= eDisplayTransactionNeeded;
-            }
-        }
-        if (what & DisplayState::eDisplaySizeChanged) {
-            if (disp.width != s.width) {
-                disp.width = s.width;
-                flags |= eDisplayTransactionNeeded;
-            }
-            if (disp.height != s.height) {
-                disp.height = s.height;
-                flags |= eDisplayTransactionNeeded;
-            }
+    DisplayDeviceState& state = mCurrentState.displays.editValueAt(index);
+
+    const uint32_t what = s.what;
+    if (what & DisplayState::eSurfaceChanged) {
+        if (IInterface::asBinder(state.surface) != IInterface::asBinder(s.surface)) {
+            state.surface = s.surface;
+            flags |= eDisplayTransactionNeeded;
         }
     }
+    if (what & DisplayState::eLayerStackChanged) {
+        if (state.layerStack != s.layerStack) {
+            state.layerStack = s.layerStack;
+            flags |= eDisplayTransactionNeeded;
+        }
+    }
+    if (what & DisplayState::eDisplayProjectionChanged) {
+        if (state.orientation != s.orientation) {
+            state.orientation = s.orientation;
+            flags |= eDisplayTransactionNeeded;
+        }
+        if (state.frame != s.frame) {
+            state.frame = s.frame;
+            flags |= eDisplayTransactionNeeded;
+        }
+        if (state.viewport != s.viewport) {
+            state.viewport = s.viewport;
+            flags |= eDisplayTransactionNeeded;
+        }
+    }
+    if (what & DisplayState::eDisplaySizeChanged) {
+        if (state.width != s.width) {
+            state.width = s.width;
+            flags |= eDisplayTransactionNeeded;
+        }
+        if (state.height != s.height) {
+            state.height = s.height;
+            flags |= eDisplayTransactionNeeded;
+        }
+    }
+
     return flags;
 }
 
@@ -3678,7 +3653,8 @@
         });
     }
 
-    ALOGD_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(), uniqueName.c_str());
+    ALOGV_IF(dupeCounter > 0, "duplicate layer name: changing %s to %s", name.c_str(),
+             uniqueName.c_str());
 
     return uniqueName;
 }
@@ -3749,13 +3725,16 @@
 // ---------------------------------------------------------------------------
 
 void SurfaceFlinger::onInitializeDisplays() {
+    const auto displayToken = mDisplayTokens[DisplayDevice::DISPLAY_PRIMARY];
+    if (!displayToken) return;
+
     // reset screen orientation and use primary layer stack
     Vector<ComposerState> state;
     Vector<DisplayState> displays;
     DisplayState d;
     d.what = DisplayState::eDisplayProjectionChanged |
              DisplayState::eLayerStackChanged;
-    d.token = mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY];
+    d.token = displayToken;
     d.layerStack = 0;
     d.orientation = DisplayState::eOrientationDefault;
     d.frame.makeInvalid();
@@ -3764,10 +3743,13 @@
     d.height = 0;
     displays.add(d);
     setTransactionState(state, displays, 0);
-    setPowerModeInternal(getDisplayDevice(d.token), HWC_POWER_MODE_NORMAL,
-                         /*stateLockHeld*/ false);
 
-    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
+    const auto display = getDisplayDevice(displayToken);
+    if (!display) return;
+
+    setPowerModeInternal(display, HWC_POWER_MODE_NORMAL, /*stateLockHeld*/ false);
+
+    const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
     const nsecs_t period = activeConfig->getVsyncPeriod();
     mAnimFrameTracker.setDisplayRefreshPeriod(period);
 
@@ -3777,51 +3759,42 @@
 }
 
 void SurfaceFlinger::initializeDisplays() {
-    class MessageScreenInitialized : public MessageBase {
-        SurfaceFlinger* flinger;
-    public:
-        explicit MessageScreenInitialized(SurfaceFlinger* flinger) : flinger(flinger) { }
-        virtual bool handler() {
-            flinger->onInitializeDisplays();
-            return true;
-        }
-    };
-    sp<MessageBase> msg = new MessageScreenInitialized(this);
-    postMessageAsync(msg);  // we may be called from main thread, use async message
+    // Async since we may be called from the main thread.
+    postMessageAsync(new LambdaMessage([this] { onInitializeDisplays(); }));
 }
 
-void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw,
-             int mode, bool stateLockHeld) {
-    ALOGD("Set power mode=%d, type=%d flinger=%p", mode, hw->getDisplayType(),
-            this);
-    int32_t type = hw->getDisplayType();
-    int currentMode = hw->getPowerMode();
+void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& display, int mode,
+                                          bool stateLockHeld) {
+    const int32_t displayId = display->getId();
+    ALOGD("Setting power mode %d on display %d", mode, displayId);
 
+    int currentMode = display->getPowerMode();
     if (mode == currentMode) {
         return;
     }
 
-    hw->setPowerMode(mode);
-    if (type >= DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES) {
+    if (display->isVirtual()) {
         ALOGW("Trying to set power mode for virtual display");
         return;
     }
 
+    display->setPowerMode(mode);
+
     if (mInterceptor->isEnabled()) {
         ConditionalLock lock(mStateLock, !stateLockHeld);
-        ssize_t idx = mCurrentState.displays.indexOfKey(hw->getDisplayToken());
+        ssize_t idx = mCurrentState.displays.indexOfKey(display->getDisplayToken());
         if (idx < 0) {
             ALOGW("Surface Interceptor SavePowerMode: invalid display token");
             return;
         }
-        mInterceptor->savePowerModeUpdate(mCurrentState.displays.valueAt(idx).displayId, mode);
+        mInterceptor->savePowerModeUpdate(mCurrentState.displays.valueAt(idx).sequenceId, mode);
     }
 
+    int32_t type = display->getDisplayType();
     if (currentMode == HWC_POWER_MODE_OFF) {
         // Turn on the display
         getHwComposer().setPowerMode(type, mode);
-        if (type == DisplayDevice::DISPLAY_PRIMARY &&
-            mode != HWC_POWER_MODE_DOZE_SUSPEND) {
+        if (display->isPrimary() && mode != HWC_POWER_MODE_DOZE_SUSPEND) {
             // FIXME: eventthread only knows about the main display right now
             mEventThread->onScreenAcquired();
             resyncToHardwareVsync(true);
@@ -3843,8 +3816,7 @@
             ALOGW("Couldn't set SCHED_OTHER on display off");
         }
 
-        if (type == DisplayDevice::DISPLAY_PRIMARY &&
-            currentMode != HWC_POWER_MODE_DOZE_SUSPEND) {
+        if (display->isPrimary() && currentMode != HWC_POWER_MODE_DOZE_SUSPEND) {
             disableHardwareVsync(true); // also cancels any in-progress resync
 
             // FIXME: eventthread only knows about the main display right now
@@ -3858,15 +3830,14 @@
                mode == HWC_POWER_MODE_NORMAL) {
         // Update display while dozing
         getHwComposer().setPowerMode(type, mode);
-        if (type == DisplayDevice::DISPLAY_PRIMARY &&
-            currentMode == HWC_POWER_MODE_DOZE_SUSPEND) {
+        if (display->isPrimary() && currentMode == HWC_POWER_MODE_DOZE_SUSPEND) {
             // FIXME: eventthread only knows about the main display right now
             mEventThread->onScreenAcquired();
             resyncToHardwareVsync(true);
         }
     } else if (mode == HWC_POWER_MODE_DOZE_SUSPEND) {
         // Leave display going to doze
-        if (type == DisplayDevice::DISPLAY_PRIMARY) {
+        if (display->isPrimary()) {
             disableHardwareVsync(true); // also cancels any in-progress resync
             // FIXME: eventthread only knows about the main display right now
             mEventThread->onScreenReleased();
@@ -3876,35 +3847,22 @@
         ALOGE("Attempting to set unknown power mode: %d\n", mode);
         getHwComposer().setPowerMode(type, mode);
     }
-    ALOGD("Finished set power mode=%d, type=%d", mode, hw->getDisplayType());
+
+    ALOGD("Finished setting power mode %d on display %d", mode, displayId);
 }
 
-void SurfaceFlinger::setPowerMode(const sp<IBinder>& display, int mode) {
-    class MessageSetPowerMode: public MessageBase {
-        SurfaceFlinger& mFlinger;
-        sp<IBinder> mDisplay;
-        int mMode;
-    public:
-        MessageSetPowerMode(SurfaceFlinger& flinger,
-                const sp<IBinder>& disp, int mode) : mFlinger(flinger),
-                    mDisplay(disp) { mMode = mode; }
-        virtual bool handler() {
-            sp<DisplayDevice> hw(mFlinger.getDisplayDevice(mDisplay));
-            if (hw == nullptr) {
-                ALOGE("Attempt to set power mode = %d for null display %p",
-                        mMode, mDisplay.get());
-            } else if (hw->getDisplayType() >= DisplayDevice::DISPLAY_VIRTUAL) {
-                ALOGW("Attempt to set power mode = %d for virtual display",
-                        mMode);
-            } else {
-                mFlinger.setPowerModeInternal(
-                        hw, mMode, /*stateLockHeld*/ false);
-            }
-            return true;
+void SurfaceFlinger::setPowerMode(const sp<IBinder>& displayToken, int mode) {
+    postMessageSync(new LambdaMessage([&] {
+        const auto display = getDisplayDevice(displayToken);
+        if (!display) {
+            ALOGE("Attempt to set power mode %d for invalid display token %p", mode,
+                  displayToken.get());
+        } else if (display->isVirtual()) {
+            ALOGW("Attempt to set power mode %d for virtual display", mode);
+        } else {
+            setPowerModeInternal(display, mode, /*stateLockHeld*/ false);
         }
-    };
-    sp<MessageBase> msg = new MessageSetPowerMode(*this, display, mode);
-    postMessageSync(msg);
+    }));
 }
 
 // ---------------------------------------------------------------------------
@@ -4014,6 +3972,13 @@
                 dumpAll = false;
             }
 
+            if ((index < numArgs) &&
+                (args[index] == String16("--display-identification"))) {
+                index++;
+                dumpDisplayIdentificationData(result);
+                dumpAll = false;
+            }
+
             if ((index < numArgs) && (args[index] == String16("--timestats"))) {
                 index++;
                 mTimeStats.parseArgs(asProto, args, index, result);
@@ -4055,9 +4020,12 @@
         index++;
     }
 
-    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
-    const nsecs_t period = activeConfig->getVsyncPeriod();
-    result.appendFormat("%" PRId64 "\n", period);
+    if (const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
+        getHwComposer().isConnected(displayId)) {
+        const auto activeConfig = getBE().mHwc->getActiveConfig(displayId);
+        const nsecs_t period = activeConfig->getVsyncPeriod();
+        result.appendFormat("%" PRId64 "\n", period);
+    }
 
     if (name.isEmpty()) {
         mAnimFrameTracker.dumpStats(result);
@@ -4193,6 +4161,48 @@
     result.append("\n");
 }
 
+void SurfaceFlinger::dumpDisplayIdentificationData(String8& result) const {
+    for (const auto& [token, display] : mDisplays) {
+        const int32_t displayId = display->getId();
+        const auto hwcDisplayId = getHwComposer().getHwcDisplayId(displayId);
+        if (!hwcDisplayId) {
+            continue;
+        }
+
+        result.appendFormat("Display %d (HWC display %" PRIu64 "): ", displayId, *hwcDisplayId);
+        uint8_t port;
+        DisplayIdentificationData data;
+        if (!getHwComposer().getDisplayIdentificationData(*hwcDisplayId, &port, &data)) {
+            result.append("no identification data\n");
+            continue;
+        }
+
+        if (!isEdid(data)) {
+            result.append("unknown identification data: ");
+            for (uint8_t byte : data) {
+                result.appendFormat("%x ", byte);
+            }
+            result.append("\n");
+            continue;
+        }
+
+        const auto edid = parseEdid(data);
+        if (!edid) {
+            result.append("invalid EDID: ");
+            for (uint8_t byte : data) {
+                result.appendFormat("%x ", byte);
+            }
+            result.append("\n");
+            continue;
+        }
+
+        result.appendFormat("port=%u pnpId=%s displayName=\"", port, edid->pnpId.data());
+        result.append(edid->displayName.data(), edid->displayName.length());
+        result.append("\"\n");
+    }
+    result.append("\n");
+}
+
 void SurfaceFlinger::dumpWideColorInfo(String8& result) const {
     result.appendFormat("hasWideColorDisplay: %d\n", hasWideColorDisplay);
     result.appendFormat("DisplayColorSetting: %s\n",
@@ -4200,20 +4210,19 @@
 
     // TODO: print out if wide-color mode is active or not
 
-    for (size_t d = 0; d < mDisplays.size(); d++) {
-        const sp<const DisplayDevice>& displayDevice(mDisplays[d]);
-        int32_t hwcId = displayDevice->getHwcDisplayId();
-        if (hwcId == DisplayDevice::DISPLAY_ID_INVALID) {
+    for (const auto& [token, display] : mDisplays) {
+        const int32_t displayId = display->getId();
+        if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
             continue;
         }
 
-        result.appendFormat("Display %d color modes:\n", hwcId);
-        std::vector<ColorMode> modes = getHwComposer().getColorModes(hwcId);
+        result.appendFormat("Display %d color modes:\n", displayId);
+        std::vector<ColorMode> modes = getHwComposer().getColorModes(displayId);
         for (auto&& mode : modes) {
             result.appendFormat("    %s (%d)\n", decodeColorMode(mode).c_str(), mode);
         }
 
-        ColorMode currentMode = displayDevice->getActiveColorMode();
+        ColorMode currentMode = display->getActiveColorMode();
         result.appendFormat("    Current color mode: %s (%d)\n",
                             decodeColorMode(currentMode).c_str(), currentMode);
     }
@@ -4232,23 +4241,22 @@
     return layersProto;
 }
 
-LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(int32_t hwcId) const {
+LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(const DisplayDevice& display) const {
     LayersProto layersProto;
-    const sp<DisplayDevice>& displayDevice(mDisplays[hwcId]);
 
     SizeProto* resolution = layersProto.mutable_resolution();
-    resolution->set_w(displayDevice->getWidth());
-    resolution->set_h(displayDevice->getHeight());
+    resolution->set_w(display.getWidth());
+    resolution->set_h(display.getHeight());
 
-    layersProto.set_color_mode(decodeColorMode(displayDevice->getActiveColorMode()));
-    layersProto.set_color_transform(decodeColorTransform(displayDevice->getColorTransform()));
-    layersProto.set_global_transform(
-            static_cast<int32_t>(displayDevice->getOrientationTransform()));
+    layersProto.set_color_mode(decodeColorMode(display.getActiveColorMode()));
+    layersProto.set_color_transform(decodeColorTransform(display.getColorTransform()));
+    layersProto.set_global_transform(static_cast<int32_t>(display.getOrientationTransform()));
 
+    const int32_t displayId = display.getId();
     mDrawingState.traverseInZOrder([&](Layer* layer) {
-        if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(hwcId)) {
+        if (!layer->visibleRegion.isEmpty() && layer->getBE().mHwcLayers.count(displayId)) {
             LayerProto* layerProto = layersProto.add_layers();
-            layer->writeToProto(layerProto, hwcId);
+            layer->writeToProto(layerProto, displayId);
         }
     });
 
@@ -4286,6 +4294,9 @@
     appendGuiConfigString(result);
     result.append("\n");
 
+    result.append("\nDisplay identification data:\n");
+    dumpDisplayIdentificationData(result);
+
     result.append("\nWide-Color information:\n");
     dumpWideColorInfo(result);
 
@@ -4295,28 +4306,32 @@
     result.append(SyncFeatures::getInstance().toString());
     result.append("\n");
 
-    const auto& activeConfig = getBE().mHwc->getActiveConfig(HWC_DISPLAY_PRIMARY);
-
     colorizer.bold(result);
-    result.append("DispSync configuration: ");
+    result.append("DispSync configuration:\n");
     colorizer.reset(result);
+
     const auto [sfEarlyOffset, appEarlyOffset] = mVsyncModulator.getEarlyOffsets();
     const auto [sfEarlyGlOffset, appEarlyGlOffset] = mVsyncModulator.getEarlyGlOffsets();
-    result.appendFormat(
-        "app phase %" PRId64 " ns, "
-        "sf phase %" PRId64 " ns, "
-        "early app phase %" PRId64 " ns, "
-        "early sf phase %" PRId64 " ns, "
-        "early app gl phase %" PRId64 " ns, "
-        "early sf gl phase %" PRId64 " ns, "
-        "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
-        vsyncPhaseOffsetNs,
-        sfVsyncPhaseOffsetNs,
-        appEarlyOffset,
-        sfEarlyOffset,
-        appEarlyGlOffset,
-        sfEarlyOffset,
-        dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
+    if (const auto displayId = DisplayDevice::DISPLAY_PRIMARY;
+        getHwComposer().isConnected(displayId)) {
+        const auto activeConfig = getHwComposer().getActiveConfig(displayId);
+        result.appendFormat("Display %d: "
+                "app phase %" PRId64 " ns, "
+                "sf phase %" PRId64 " ns, "
+                "early app phase %" PRId64 " ns, "
+                "early sf phase %" PRId64 " ns, "
+                "early app gl phase %" PRId64 " ns, "
+                "early sf gl phase %" PRId64 " ns, "
+                "present offset %" PRId64 " ns (refresh %" PRId64 " ns)",
+                displayId,
+                vsyncPhaseOffsetNs,
+                sfVsyncPhaseOffsetNs,
+                appEarlyOffset,
+                sfEarlyOffset,
+                appEarlyGlOffset,
+                sfEarlyOffset,
+                dispSyncPresentTimeOffset, activeConfig->getVsyncPeriod());
+    }
     result.append("\n");
 
     // Dump static screen stats
@@ -4324,6 +4339,8 @@
     dumpStaticScreenStats(result);
     result.append("\n");
 
+    result.appendFormat("Missed frame count: %u\n\n", mFrameMissedCount.load());
+
     dumpBufferingStats(result);
 
     /*
@@ -4347,9 +4364,8 @@
     colorizer.bold(result);
     result.appendFormat("Displays (%zu entries)\n", mDisplays.size());
     colorizer.reset(result);
-    for (size_t dpy=0 ; dpy<mDisplays.size() ; dpy++) {
-        const sp<const DisplayDevice>& hw(mDisplays[dpy]);
-        hw->dump(result);
+    for (const auto& [token, display] : mDisplays) {
+        display->dump(result);
     }
     result.append("\n");
 
@@ -4362,31 +4378,30 @@
     colorizer.reset(result);
 
     HWComposer& hwc(getHwComposer());
-    sp<const DisplayDevice> hw(getDefaultDisplayDeviceLocked());
+    const auto display = getDefaultDisplayDeviceLocked();
 
     getBE().mRenderEngine->dump(result);
 
-    if (hw) {
-        hw->undefinedRegion.dump(result, "undefinedRegion");
-        result.appendFormat("  orientation=%d, isDisplayOn=%d\n",
-                hw->getOrientation(), hw->isDisplayOn());
+    if (display) {
+        display->undefinedRegion.dump(result, "undefinedRegion");
+        result.appendFormat("  orientation=%d, isPoweredOn=%d\n", display->getOrientation(),
+                            display->isPoweredOn());
     }
-    result.appendFormat(
-            "  last eglSwapBuffers() time: %f us\n"
-            "  last transaction time     : %f us\n"
-            "  transaction-flags         : %08x\n"
-            "  refresh-rate              : %f fps\n"
-            "  x-dpi                     : %f\n"
-            "  y-dpi                     : %f\n"
-            "  gpu_to_cpu_unsupported    : %d\n"
-            ,
-            mLastSwapBufferTime/1000.0,
-            mLastTransactionTime/1000.0,
-            mTransactionFlags,
-            1e9 / activeConfig->getVsyncPeriod(),
-            activeConfig->getDpiX(),
-            activeConfig->getDpiY(),
-            !mGpuToCpuSupported);
+    result.appendFormat("  last eglSwapBuffers() time: %f us\n"
+                        "  last transaction time     : %f us\n"
+                        "  transaction-flags         : %08x\n"
+                        "  gpu_to_cpu_unsupported    : %d\n",
+                        mLastSwapBufferTime / 1000.0, mLastTransactionTime / 1000.0,
+                        mTransactionFlags, !mGpuToCpuSupported);
+
+    if (display) {
+        const auto activeConfig = getHwComposer().getActiveConfig(display->getId());
+        result.appendFormat("  refresh-rate              : %f fps\n"
+                            "  x-dpi                     : %f\n"
+                            "  y-dpi                     : %f\n",
+                            1e9 / activeConfig->getVsyncPeriod(), activeConfig->getDpiX(),
+                            activeConfig->getDpiY());
+    }
 
     result.appendFormat("  eglSwapBuffers time: %f us\n",
             inSwapBuffersDuration/1000.0);
@@ -4403,18 +4418,15 @@
     /*
      * HWC layer minidump
      */
-    for (size_t d = 0; d < mDisplays.size(); d++) {
-        const sp<const DisplayDevice>& displayDevice(mDisplays[d]);
-        int32_t hwcId = displayDevice->getHwcDisplayId();
-        if (hwcId == DisplayDevice::DISPLAY_ID_INVALID) {
+    for (const auto& [token, display] : mDisplays) {
+        const int32_t displayId = display->getId();
+        if (displayId == DisplayDevice::DISPLAY_ID_INVALID) {
             continue;
         }
 
-        result.appendFormat("Display %d HWC layers:\n", hwcId);
+        result.appendFormat("Display %d HWC layers:\n", displayId);
         Layer::miniDumpHeader(result);
-        mCurrentState.traverseInZOrder([&](Layer* layer) {
-            layer->miniDump(result, hwcId);
-        });
+        mCurrentState.traverseInZOrder([&](Layer* layer) { layer->miniDump(result, displayId); });
         result.append("\n");
     }
 
@@ -4445,22 +4457,17 @@
     }
 }
 
-const Vector< sp<Layer> >&
-SurfaceFlinger::getLayerSortedByZForHwcDisplay(int id) {
+const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(int32_t displayId) {
     // Note: mStateLock is held here
-    wp<IBinder> dpy;
-    for (size_t i=0 ; i<mDisplays.size() ; i++) {
-        if (mDisplays.valueAt(i)->getHwcDisplayId() == id) {
-            dpy = mDisplays.keyAt(i);
-            break;
+    for (const auto& [token, display] : mDisplays) {
+        if (display->getId() == displayId) {
+            return getDisplayDeviceLocked(token)->getVisibleLayersSortedByZ();
         }
     }
-    if (dpy == nullptr) {
-        ALOGE("getLayerSortedByZForHwcDisplay: invalid hwc display id %d", id);
-        // Just use the primary display so we have something to return
-        dpy = getBuiltInDisplay(DisplayDevice::DISPLAY_PRIMARY);
-    }
-    return getDisplayDeviceLocked(dpy)->getVisibleLayersSortedByZ();
+
+    ALOGE("%s: Invalid display %d", __FUNCTION__, displayId);
+    static const Vector<sp<Layer>> empty;
+    return empty;
 }
 
 bool SurfaceFlinger::startDdmConnection()
@@ -4632,8 +4639,12 @@
                 reply->writeInt32(mDebugDisableHWC);
                 return NO_ERROR;
             case 1013: {
-                sp<const DisplayDevice> hw(getDefaultDisplayDevice());
-                reply->writeInt32(hw->getPageFlipCount());
+                const auto display = getDefaultDisplayDevice();
+                if (!display) {
+                    return NAME_NOT_FOUND;
+                }
+
+                reply->writeInt32(display->getPageFlipCount());
                 return NO_ERROR;
             }
             case 1014: {
@@ -4764,8 +4775,8 @@
             }
             // Is a DisplayColorSetting supported?
             case 1027: {
-                sp<const DisplayDevice> hw(getDefaultDisplayDevice());
-                if (!hw) {
+                const auto display = getDefaultDisplayDevice();
+                if (!display) {
                     return NAME_NOT_FOUND;
                 }
 
@@ -4778,14 +4789,21 @@
                         reply->writeBool(true);
                         break;
                     case DisplayColorSetting::ENHANCED:
-                        reply->writeBool(hw->hasRenderIntent(RenderIntent::ENHANCE));
+                        reply->writeBool(display->hasRenderIntent(RenderIntent::ENHANCE));
                         break;
                     default: // vendor display color setting
-                        reply->writeBool(hw->hasRenderIntent(static_cast<RenderIntent>(setting)));
+                        reply->writeBool(
+                                display->hasRenderIntent(static_cast<RenderIntent>(setting)));
                         break;
                 }
                 return NO_ERROR;
             }
+            // Is VrFlinger active?
+            case 1028: {
+                Mutex::Autolock _l(mStateLock);
+                reply->writeBool(getBE().mHwc->isUsingVrComposer());
+                return NO_ERROR;
+            }
         }
     }
     return err;
@@ -4809,22 +4827,22 @@
     const int mApi;
 };
 
-status_t SurfaceFlinger::captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
-                                       Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
-                                       int32_t minLayerZ, int32_t maxLayerZ,
-                                       bool useIdentityTransform,
+status_t SurfaceFlinger::captureScreen(const sp<IBinder>& displayToken,
+                                       sp<GraphicBuffer>* outBuffer, Rect sourceCrop,
+                                       uint32_t reqWidth, uint32_t reqHeight, int32_t minLayerZ,
+                                       int32_t maxLayerZ, bool useIdentityTransform,
                                        ISurfaceComposer::Rotation rotation) {
     ATRACE_CALL();
 
-    if (CC_UNLIKELY(display == 0)) return BAD_VALUE;
+    if (!displayToken) return BAD_VALUE;
 
-    const sp<const DisplayDevice> device(getDisplayDeviceLocked(display));
-    if (CC_UNLIKELY(device == 0)) return BAD_VALUE;
+    const auto display = getDisplayDeviceLocked(displayToken);
+    if (!display) return BAD_VALUE;
 
-    DisplayRenderArea renderArea(device, sourceCrop, reqHeight, reqWidth, rotation);
+    DisplayRenderArea renderArea(display, sourceCrop, reqHeight, reqWidth, rotation);
 
     auto traverseLayers = std::bind(std::mem_fn(&SurfaceFlinger::traverseLayersInDisplay), this,
-                                    device, minLayerZ, maxLayerZ, std::placeholders::_1);
+                                    display, minLayerZ, maxLayerZ, std::placeholders::_1);
     return captureScreenCommon(renderArea, traverseLayers, outBuffer, useIdentityTransform);
 }
 
@@ -4966,7 +4984,7 @@
     const int uid = IPCThreadState::self()->getCallingUid();
     const bool forSystem = uid == AID_GRAPHICS || uid == AID_SYSTEM;
 
-    sp<LambdaMessage> message = new LambdaMessage([&]() {
+    sp<LambdaMessage> message = new LambdaMessage([&] {
         // If there is a refresh pending, bug out early and tell the binder thread to try again
         // after the refresh.
         if (mRefreshPending) {
@@ -4981,7 +4999,7 @@
         int fd = -1;
         {
             Mutex::Autolock _l(mStateLock);
-            renderArea.render([&]() {
+            renderArea.render([&] {
                 result = captureScreenImplLocked(renderArea, traverseLayers, (*outBuffer).get(),
                                                  useIdentityTransform, forSystem, &fd);
             });
@@ -4997,14 +5015,14 @@
 
     status_t result = postMessageAsync(message);
     if (result == NO_ERROR) {
-        captureCondition.wait(captureLock, [&]() { return captureResult; });
+        captureCondition.wait(captureLock, [&] { return captureResult; });
         while (*captureResult == EAGAIN) {
             captureResult.reset();
             result = postMessageAsync(message);
             if (result != NO_ERROR) {
                 return result;
             }
-            captureCondition.wait(captureLock, [&]() { return captureResult; });
+            captureCondition.wait(captureLock, [&] { return captureResult; });
         }
         result = *captureResult;
     }
@@ -5126,7 +5144,7 @@
 
     traverseLayers([&](Layer* layer) {
         if (filtering) layer->setFiltering(true);
-        layer->draw(renderArea, useIdentityTransform);
+        layer->drawNow(renderArea, useIdentityTransform);
         if (filtering) layer->setFiltering(false);
     });
 }
@@ -5222,13 +5240,13 @@
     layersSortedByZ.traverseInReverseZOrder(stateSet, visitor);
 }
 
-void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& hw, int32_t minLayerZ,
-                                             int32_t maxLayerZ,
+void SurfaceFlinger::traverseLayersInDisplay(const sp<const DisplayDevice>& display,
+                                             int32_t minLayerZ, int32_t maxLayerZ,
                                              const LayerVector::Visitor& visitor) {
     // We loop through the first level of layers without traversing,
     // as we need to interpret min/max layer Z in the top level Z space.
     for (const auto& layer : mDrawingState.layersSortedByZ) {
-        if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
+        if (!layer->belongsToDisplay(display->getLayerStack(), false)) {
             continue;
         }
         const Layer::State& state(layer->getDrawingState());
@@ -5237,7 +5255,7 @@
             continue;
         }
         layer->traverseInZOrder(LayerVector::StateSet::Drawing, [&](Layer* layer) {
-            if (!layer->belongsToDisplay(hw->getLayerStack(), false)) {
+            if (!layer->belongsToDisplay(display->getLayerStack(), false)) {
                 return;
             }
             if (!layer->isVisible()) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 8f724e9..e107f42 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -45,6 +45,7 @@
 #include <gui/LayerState.h>
 
 #include <gui/OccupancyTracker.h>
+#include <gui/BufferQueue.h>
 
 #include <hardware/hwcomposer_defs.h>
 
@@ -64,6 +65,7 @@
 #include "SurfaceTracing.h"
 #include "StartPropertySetThread.h"
 #include "TimeStats/TimeStats.h"
+#include "LayerBE.h"
 #include "VSyncModulator.h"
 
 #include "DisplayHardware/HWC2.h"
@@ -410,7 +412,7 @@
     virtual sp<ISurfaceComposerClient> createConnection();
     virtual sp<ISurfaceComposerClient> createScopedConnection(const sp<IGraphicBufferProducer>& gbp);
     virtual sp<IBinder> createDisplay(const String8& displayName, bool secure);
-    virtual void destroyDisplay(const sp<IBinder>& display);
+    virtual void destroyDisplay(const sp<IBinder>& displayToken);
     virtual sp<IBinder> getBuiltInDisplay(int32_t id);
     virtual void setTransactionState(const Vector<ComposerState>& state,
             const Vector<DisplayState>& displays, uint32_t flags);
@@ -421,27 +423,26 @@
             std::vector<FrameEvent>* outSupported) const;
     virtual sp<IDisplayEventConnection> createDisplayEventConnection(
             ISurfaceComposer::VsyncSource vsyncSource = eVsyncSourceApp);
-    virtual status_t captureScreen(const sp<IBinder>& display, sp<GraphicBuffer>* outBuffer,
+    virtual status_t captureScreen(const sp<IBinder>& displayToken, sp<GraphicBuffer>* outBuffer,
                                    Rect sourceCrop, uint32_t reqWidth, uint32_t reqHeight,
                                    int32_t minLayerZ, int32_t maxLayerZ, bool useIdentityTransform,
                                    ISurfaceComposer::Rotation rotation);
     virtual status_t captureLayers(const sp<IBinder>& parentHandle, sp<GraphicBuffer>* outBuffer,
                                    const Rect& sourceCrop, float frameScale, bool childrenOnly);
-    virtual status_t getDisplayStats(const sp<IBinder>& display,
-            DisplayStatInfo* stats);
-    virtual status_t getDisplayConfigs(const sp<IBinder>& display,
-            Vector<DisplayInfo>* configs);
-    virtual int getActiveConfig(const sp<IBinder>& display);
-    virtual status_t getDisplayColorModes(const sp<IBinder>& display,
-            Vector<ui::ColorMode>* configs);
-    virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& display);
-    virtual status_t setActiveColorMode(const sp<IBinder>& display, ui::ColorMode colorMode);
-    virtual void setPowerMode(const sp<IBinder>& display, int mode);
-    virtual status_t setActiveConfig(const sp<IBinder>& display, int id);
+    virtual status_t getDisplayStats(const sp<IBinder>& displayToken, DisplayStatInfo* stats);
+    virtual status_t getDisplayConfigs(const sp<IBinder>& displayToken,
+                                       Vector<DisplayInfo>* configs);
+    virtual int getActiveConfig(const sp<IBinder>& displayToken);
+    virtual status_t getDisplayColorModes(const sp<IBinder>& displayToken,
+                                          Vector<ui::ColorMode>* configs);
+    virtual ui::ColorMode getActiveColorMode(const sp<IBinder>& displayToken);
+    virtual status_t setActiveColorMode(const sp<IBinder>& displayToken, ui::ColorMode colorMode);
+    virtual void setPowerMode(const sp<IBinder>& displayToken, int mode);
+    virtual status_t setActiveConfig(const sp<IBinder>& displayToken, int id);
     virtual status_t clearAnimationFrameStats();
     virtual status_t getAnimationFrameStats(FrameStats* outStats) const;
-    virtual status_t getHdrCapabilities(const sp<IBinder>& display,
-            HdrCapabilities* outCapabilities) const;
+    virtual status_t getHdrCapabilities(const sp<IBinder>& displayToken,
+                                        HdrCapabilities* outCapabilities) const;
     virtual status_t enableVSyncInjections(bool enable);
     virtual status_t injectVSync(nsecs_t when);
     virtual status_t getLayerDebugInfo(std::vector<LayerDebugInfo>* outLayers) const;
@@ -460,11 +461,11 @@
     /* ------------------------------------------------------------------------
      * HWC2::ComposerCallback / HWComposer::EventHandler interface
      */
-    void onVsyncReceived(int32_t sequenceId, hwc2_display_t display,
+    void onVsyncReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
                          int64_t timestamp) override;
-    void onHotplugReceived(int32_t sequenceId, hwc2_display_t display,
+    void onHotplugReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId,
                            HWC2::Connection connection) override;
-    void onRefreshReceived(int32_t sequenceId, hwc2_display_t display) override;
+    void onRefreshReceived(int32_t sequenceId, hwc2_display_t hwcDisplayId) override;
 
     /* ------------------------------------------------------------------------
      * Message handling
@@ -479,16 +480,13 @@
     // called on the main thread in response to initializeDisplays()
     void onInitializeDisplays();
     // called on the main thread in response to setActiveConfig()
-    void setActiveConfigInternal(const sp<DisplayDevice>& hw, int mode);
+    void setActiveConfigInternal(const sp<DisplayDevice>& display, int mode);
     // called on the main thread in response to setPowerMode()
-    void setPowerModeInternal(const sp<DisplayDevice>& hw, int mode,
-                              bool stateLockHeld);
+    void setPowerModeInternal(const sp<DisplayDevice>& display, int mode, bool stateLockHeld);
 
     // Called on the main thread in response to setActiveColorMode()
-    void setActiveColorModeInternal(const sp<DisplayDevice>& hw,
-                                    ui::ColorMode colorMode,
-                                    ui::Dataspace dataSpace,
-                                    ui::RenderIntent renderIntent);
+    void setActiveColorModeInternal(const sp<DisplayDevice>& display, ui::ColorMode colorMode,
+                                    ui::Dataspace dataSpace, ui::RenderIntent renderIntent);
 
     // Returns whether the transaction actually modified any state
     bool handleMessageTransaction();
@@ -599,38 +597,33 @@
     // called when starting, or restarting after system_server death
     void initializeDisplays();
 
-    sp<const DisplayDevice> getDisplayDevice(const wp<IBinder>& dpy) const {
-      Mutex::Autolock _l(mStateLock);
-      return getDisplayDeviceLocked(dpy);
+    sp<const DisplayDevice> getDisplayDevice(const wp<IBinder>& displayToken) const {
+        Mutex::Autolock _l(mStateLock);
+        return getDisplayDeviceLocked(displayToken);
     }
 
-    sp<DisplayDevice> getDisplayDevice(const wp<IBinder>& dpy) {
-      Mutex::Autolock _l(mStateLock);
-      return getDisplayDeviceLocked(dpy);
+    sp<DisplayDevice> getDisplayDevice(const wp<IBinder>& displayToken) {
+        Mutex::Autolock _l(mStateLock);
+        return getDisplayDeviceLocked(displayToken);
     }
 
     // NOTE: can only be called from the main thread or with mStateLock held
-    sp<const DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& dpy) const {
-        return mDisplays.valueFor(dpy);
+    sp<const DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) const {
+        return const_cast<SurfaceFlinger*>(this)->getDisplayDeviceLocked(displayToken);
     }
 
     // NOTE: can only be called from the main thread or with mStateLock held
-    sp<DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& dpy) {
-        return mDisplays.valueFor(dpy);
+    sp<DisplayDevice> getDisplayDeviceLocked(const wp<IBinder>& displayToken) {
+        const auto it = mDisplays.find(displayToken);
+        return it == mDisplays.end() ? nullptr : it->second;
     }
 
     sp<const DisplayDevice> getDefaultDisplayDeviceLocked() const {
-        return getDisplayDeviceLocked(mBuiltinDisplays[DisplayDevice::DISPLAY_PRIMARY]);
+        return const_cast<SurfaceFlinger*>(this)->getDefaultDisplayDeviceLocked();
     }
 
-    int32_t getDisplayType(const sp<IBinder>& display) {
-        if (!display.get()) return NAME_NOT_FOUND;
-        for (int i = 0; i < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES; ++i) {
-            if (display == mBuiltinDisplays[i]) {
-                return i;
-            }
-        }
-        return NAME_NOT_FOUND;
+    sp<DisplayDevice> getDefaultDisplayDeviceLocked() {
+        return getDisplayDeviceLocked(mDisplayTokens[DisplayDevice::DISPLAY_PRIMARY]);
     }
 
     // mark a region of a layer stack dirty. this updates the dirty
@@ -647,8 +640,8 @@
      * Compositing
      */
     void invalidateHwcGeometry();
-    void computeVisibleRegions(const sp<const DisplayDevice>& displayDevice,
-            Region& dirtyRegion, Region& opaqueRegion);
+    void computeVisibleRegions(const sp<const DisplayDevice>& display, Region& dirtyRegion,
+                               Region& opaqueRegion);
 
     void preComposition(nsecs_t refreshStartTime);
     void postComposition(nsecs_t refreshStartTime);
@@ -660,37 +653,35 @@
             nsecs_t compositeToPresentLatency);
     void rebuildLayerStacks();
 
-    ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& displayDevice,
+    ui::Dataspace getBestDataspace(const sp<const DisplayDevice>& display,
                                    ui::Dataspace* outHdrDataSpace) const;
 
     // Returns the appropriate ColorMode, Dataspace and RenderIntent for the
     // DisplayDevice. The function only returns the supported ColorMode,
     // Dataspace and RenderIntent.
-    void pickColorMode(const sp<DisplayDevice>& displayDevice,
-                       ui::ColorMode* outMode,
-                       ui::Dataspace* outDataSpace,
-                       ui::RenderIntent* outRenderIntent) const;
+    void pickColorMode(const sp<DisplayDevice>& display, ui::ColorMode* outMode,
+                       ui::Dataspace* outDataSpace, ui::RenderIntent* outRenderIntent) const;
 
     void setUpHWComposer();
     void doComposition();
     void doDebugFlashRegions();
     void doTracing(const char* where);
     void logLayerStats();
-    void doDisplayComposition(const sp<const DisplayDevice>& displayDevice, const Region& dirtyRegion);
+    void doDisplayComposition(const sp<const DisplayDevice>& display, const Region& dirtyRegion);
 
-    // compose surfaces for display hw. this fails if using GL and the surface
-    // has been destroyed and is no longer valid.
-    bool doComposeSurfaces(const sp<const DisplayDevice>& displayDevice);
+    // This fails if using GL and the surface has been destroyed.
+    bool doComposeSurfaces(const sp<const DisplayDevice>& display);
 
     void postFramebuffer();
-    void drawWormhole(const sp<const DisplayDevice>& displayDevice, const Region& region) const;
+    void drawWormhole(const sp<const DisplayDevice>& display, const Region& region) const;
 
     /* ------------------------------------------------------------------------
      * Display management
      */
-    DisplayDevice::DisplayType determineDisplayType(hwc2_display_t display,
-            HWC2::Connection connection) const;
-    sp<DisplayDevice> setupNewDisplayDeviceInternal(const wp<IBinder>& display, int hwcId,
+    DisplayDevice::DisplayType determineDisplayType(hwc2_display_t hwcDisplayId,
+                                                    HWC2::Connection connection) const;
+    sp<DisplayDevice> setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken,
+                                                    int32_t displayId,
                                                     const DisplayDeviceState& state,
                                                     const sp<DisplaySurface>& dispSurface,
                                                     const sp<IGraphicBufferProducer>& producer);
@@ -740,9 +731,10 @@
     void recordBufferingStats(const char* layerName,
             std::vector<OccupancyTracker::Segment>&& history);
     void dumpBufferingStats(String8& result) const;
+    void dumpDisplayIdentificationData(String8& result) const;
     void dumpWideColorInfo(String8& result) const;
     LayersProto dumpProtoInfo(LayerVector::StateSet stateSet) const;
-    LayersProto dumpVisibleLayersProtoInfo(int32_t hwcId) const;
+    LayersProto dumpVisibleLayersProtoInfo(const DisplayDevice& display) const;
 
     bool isLayerTripleBufferingDisabled() const {
         return this->mLayerTripleBufferingDisabled;
@@ -798,7 +790,7 @@
     std::unique_ptr<VSyncSource> mSfEventThreadSource;
     std::unique_ptr<InjectVSyncSource> mVSyncInjector;
     std::unique_ptr<EventControlThread> mEventControlThread;
-    sp<IBinder> mBuiltinDisplays[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
+    sp<IBinder> mDisplayTokens[DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES];
 
     VSyncModulator mVsyncModulator;
 
@@ -820,7 +812,7 @@
     BootStage mBootStage;
 
     struct HotplugEvent {
-        hwc2_display_t display;
+        hwc2_display_t hwcDisplayId;
         HWC2::Connection connection = HWC2::Connection::Invalid;
     };
     // protected by mStateLock
@@ -828,7 +820,7 @@
 
     // this may only be written from the main thread with mStateLock held
     // it may be read from other threads with mStateLock held
-    DefaultKeyedVector< wp<IBinder>, sp<DisplayDevice> > mDisplays;
+    std::map<wp<IBinder>, sp<DisplayDevice>> mDisplays;
 
     // don't use a lock for these, we don't care
     int mDebugRegion;
@@ -847,6 +839,7 @@
     LayerStats mLayerStats;
     TimeStats& mTimeStats = TimeStats::getInstance();
     bool mUseHwcVirtualDisplays = false;
+    std::atomic<uint32_t> mFrameMissedCount{0};
 
     // Restrict layers to use two buffers in their bufferqueues.
     bool mLayerTripleBufferingDisabled = false;
diff --git a/services/surfaceflinger/SurfaceInterceptor.cpp b/services/surfaceflinger/SurfaceInterceptor.cpp
index 4596a21..e70506d 100644
--- a/services/surfaceflinger/SurfaceInterceptor.cpp
+++ b/services/surfaceflinger/SurfaceInterceptor.cpp
@@ -122,10 +122,10 @@
     transaction->set_synchronous(false);
     transaction->set_animation(false);
 
-    addDisplaySurfaceLocked(transaction, display.displayId, display.surface);
-    addDisplayLayerStackLocked(transaction, display.displayId, display.layerStack);
-    addDisplaySizeLocked(transaction, display.displayId, display.width, display.height);
-    addDisplayProjectionLocked(transaction, display.displayId, display.orientation,
+    addDisplaySurfaceLocked(transaction, display.sequenceId, display.surface);
+    addDisplayLayerStackLocked(transaction, display.sequenceId, display.layerStack);
+    addDisplaySizeLocked(transaction, display.sequenceId, display.width, display.height);
+    addDisplayProjectionLocked(transaction, display.sequenceId, display.orientation,
             display.viewport, display.frame);
 }
 
@@ -177,10 +177,10 @@
 }
 
 DisplayChange* SurfaceInterceptor::createDisplayChangeLocked(Transaction* transaction,
-        int32_t displayId)
+        int32_t sequenceId)
 {
     DisplayChange* dispChange(transaction->add_display_change());
-    dispChange->set_id(displayId);
+    dispChange->set_id(sequenceId);
     return dispChange;
 }
 
@@ -379,19 +379,19 @@
 }
 
 void SurfaceInterceptor::addDisplayChangesLocked(Transaction* transaction,
-        const DisplayState& state, int32_t displayId)
+        const DisplayState& state, int32_t sequenceId)
 {
     if (state.what & DisplayState::eSurfaceChanged) {
-        addDisplaySurfaceLocked(transaction, displayId, state.surface);
+        addDisplaySurfaceLocked(transaction, sequenceId, state.surface);
     }
     if (state.what & DisplayState::eLayerStackChanged) {
-        addDisplayLayerStackLocked(transaction, displayId, state.layerStack);
+        addDisplayLayerStackLocked(transaction, sequenceId, state.layerStack);
     }
     if (state.what & DisplayState::eDisplaySizeChanged) {
-        addDisplaySizeLocked(transaction, displayId, state.width, state.height);
+        addDisplaySizeLocked(transaction, sequenceId, state.width, state.height);
     }
     if (state.what & DisplayState::eDisplayProjectionChanged) {
-        addDisplayProjectionLocked(transaction, displayId, state.orientation, state.viewport,
+        addDisplayProjectionLocked(transaction, sequenceId, state.orientation, state.viewport,
                 state.frame);
     }
 }
@@ -411,7 +411,7 @@
         ssize_t dpyIdx = displays.indexOfKey(disp.token);
         if (dpyIdx >= 0) {
             const DisplayDeviceState& dispState(displays.valueAt(dpyIdx));
-            addDisplayChangesLocked(transaction, disp, dispState.displayId);
+            addDisplayChangesLocked(transaction, disp, dispState.sequenceId);
         }
     }
 }
@@ -448,7 +448,7 @@
     event->set_when(timestamp);
 }
 
-void SurfaceInterceptor::addDisplaySurfaceLocked(Transaction* transaction, int32_t displayId,
+void SurfaceInterceptor::addDisplaySurfaceLocked(Transaction* transaction, int32_t sequenceId,
         const sp<const IGraphicBufferProducer>& surface)
 {
     if (surface == nullptr) {
@@ -457,7 +457,7 @@
     uint64_t bufferQueueId = 0;
     status_t err(surface->getUniqueId(&bufferQueueId));
     if (err == NO_ERROR) {
-        DisplayChange* dispChange(createDisplayChangeLocked(transaction, displayId));
+        DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
         DispSurfaceChange* surfaceChange(dispChange->mutable_surface());
         surfaceChange->set_buffer_queue_id(bufferQueueId);
         surfaceChange->set_buffer_queue_name(surface->getConsumerName().string());
@@ -469,26 +469,26 @@
 }
 
 void SurfaceInterceptor::addDisplayLayerStackLocked(Transaction* transaction,
-        int32_t displayId, uint32_t layerStack)
+        int32_t sequenceId, uint32_t layerStack)
 {
-    DisplayChange* dispChange(createDisplayChangeLocked(transaction, displayId));
+    DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
     LayerStackChange* layerStackChange(dispChange->mutable_layer_stack());
     layerStackChange->set_layer_stack(layerStack);
 }
 
-void SurfaceInterceptor::addDisplaySizeLocked(Transaction* transaction, int32_t displayId,
+void SurfaceInterceptor::addDisplaySizeLocked(Transaction* transaction, int32_t sequenceId,
         uint32_t w, uint32_t h)
 {
-    DisplayChange* dispChange(createDisplayChangeLocked(transaction, displayId));
+    DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
     SizeChange* sizeChange(dispChange->mutable_size());
     sizeChange->set_w(w);
     sizeChange->set_h(h);
 }
 
 void SurfaceInterceptor::addDisplayProjectionLocked(Transaction* transaction,
-        int32_t displayId, int32_t orientation, const Rect& viewport, const Rect& frame)
+        int32_t sequenceId, int32_t orientation, const Rect& viewport, const Rect& frame)
 {
-    DisplayChange* dispChange(createDisplayChangeLocked(transaction, displayId));
+    DisplayChange* dispChange(createDisplayChangeLocked(transaction, sequenceId));
     ProjectionChange* projectionChange(dispChange->mutable_projection());
     projectionChange->set_orientation(orientation);
     Rectangle* viewportRect(projectionChange->mutable_viewport());
@@ -501,22 +501,22 @@
         const DisplayDeviceState& info)
 {
     DisplayCreation* creation(increment->mutable_display_creation());
-    creation->set_id(info.displayId);
+    creation->set_id(info.sequenceId);
     creation->set_name(info.displayName);
     creation->set_type(info.type);
     creation->set_is_secure(info.isSecure);
 }
 
-void SurfaceInterceptor::addDisplayDeletionLocked(Increment* increment, int32_t displayId) {
+void SurfaceInterceptor::addDisplayDeletionLocked(Increment* increment, int32_t sequenceId) {
     DisplayDeletion* deletion(increment->mutable_display_deletion());
-    deletion->set_id(displayId);
+    deletion->set_id(sequenceId);
 }
 
-void SurfaceInterceptor::addPowerModeUpdateLocked(Increment* increment, int32_t displayId,
+void SurfaceInterceptor::addPowerModeUpdateLocked(Increment* increment, int32_t sequenceId,
         int32_t mode)
 {
     PowerModeUpdate* powerModeUpdate(increment->mutable_power_mode_update());
-    powerModeUpdate->set_id(displayId);
+    powerModeUpdate->set_id(sequenceId);
     powerModeUpdate->set_mode(mode);
 }
 
@@ -579,22 +579,22 @@
     addDisplayCreationLocked(createTraceIncrementLocked(), info);
 }
 
-void SurfaceInterceptor::saveDisplayDeletion(int32_t displayId) {
+void SurfaceInterceptor::saveDisplayDeletion(int32_t sequenceId) {
     if (!mEnabled) {
         return;
     }
     ATRACE_CALL();
     std::lock_guard<std::mutex> protoGuard(mTraceMutex);
-    addDisplayDeletionLocked(createTraceIncrementLocked(), displayId);
+    addDisplayDeletionLocked(createTraceIncrementLocked(), sequenceId);
 }
 
-void SurfaceInterceptor::savePowerModeUpdate(int32_t displayId, int32_t mode) {
+void SurfaceInterceptor::savePowerModeUpdate(int32_t sequenceId, int32_t mode) {
     if (!mEnabled) {
         return;
     }
     ATRACE_CALL();
     std::lock_guard<std::mutex> protoGuard(mTraceMutex);
-    addPowerModeUpdateLocked(createTraceIncrementLocked(), displayId, mode);
+    addPowerModeUpdateLocked(createTraceIncrementLocked(), sequenceId, mode);
 }
 
 } // namespace impl
diff --git a/services/surfaceflinger/SurfaceInterceptor.h b/services/surfaceflinger/SurfaceInterceptor.h
index 96defcc..218a1d2 100644
--- a/services/surfaceflinger/SurfaceInterceptor.h
+++ b/services/surfaceflinger/SurfaceInterceptor.h
@@ -66,8 +66,8 @@
 
     // Intercept display data
     virtual void saveDisplayCreation(const DisplayDeviceState& info) = 0;
-    virtual void saveDisplayDeletion(int32_t displayId) = 0;
-    virtual void savePowerModeUpdate(int32_t displayId, int32_t mode) = 0;
+    virtual void saveDisplayDeletion(int32_t sequenceId) = 0;
+    virtual void savePowerModeUpdate(int32_t sequenceId, int32_t mode) = 0;
     virtual void saveVSyncEvent(nsecs_t timestamp) = 0;
 };
 
@@ -101,8 +101,8 @@
 
     // Intercept display data
     void saveDisplayCreation(const DisplayDeviceState& info) override;
-    void saveDisplayDeletion(int32_t displayId) override;
-    void savePowerModeUpdate(int32_t displayId, int32_t mode) override;
+    void saveDisplayDeletion(int32_t sequenceId) override;
+    void savePowerModeUpdate(int32_t sequenceId, int32_t mode) override;
     void saveVSyncEvent(nsecs_t timestamp) override;
 
 private:
@@ -127,8 +127,8 @@
             uint32_t height, uint64_t frameNumber);
     void addVSyncUpdateLocked(Increment* increment, nsecs_t timestamp);
     void addDisplayCreationLocked(Increment* increment, const DisplayDeviceState& info);
-    void addDisplayDeletionLocked(Increment* increment, int32_t displayId);
-    void addPowerModeUpdateLocked(Increment* increment, int32_t displayId, int32_t mode);
+    void addDisplayDeletionLocked(Increment* increment, int32_t sequenceId);
+    void addPowerModeUpdateLocked(Increment* increment, int32_t sequenceId, int32_t mode);
 
     // Add surface transactions to the trace
     SurfaceChange* createSurfaceChangeLocked(Transaction* transaction, int32_t layerId);
@@ -155,17 +155,17 @@
             const Vector<DisplayState>& changedDisplays, uint32_t transactionFlags);
 
     // Add display transactions to the trace
-    DisplayChange* createDisplayChangeLocked(Transaction* transaction, int32_t displayId);
-    void addDisplaySurfaceLocked(Transaction* transaction, int32_t displayId,
+    DisplayChange* createDisplayChangeLocked(Transaction* transaction, int32_t sequenceId);
+    void addDisplaySurfaceLocked(Transaction* transaction, int32_t sequenceId,
             const sp<const IGraphicBufferProducer>& surface);
-    void addDisplayLayerStackLocked(Transaction* transaction, int32_t displayId,
+    void addDisplayLayerStackLocked(Transaction* transaction, int32_t sequenceId,
             uint32_t layerStack);
-    void addDisplaySizeLocked(Transaction* transaction, int32_t displayId, uint32_t w,
+    void addDisplaySizeLocked(Transaction* transaction, int32_t sequenceId, uint32_t w,
             uint32_t h);
-    void addDisplayProjectionLocked(Transaction* transaction, int32_t displayId,
+    void addDisplayProjectionLocked(Transaction* transaction, int32_t sequenceId,
             int32_t orientation, const Rect& viewport, const Rect& frame);
     void addDisplayChangesLocked(Transaction* transaction,
-            const DisplayState& state, int32_t displayId);
+            const DisplayState& state, int32_t sequenceId);
 
 
     bool mEnabled {false};
diff --git a/services/surfaceflinger/SurfaceTracing.cpp b/services/surfaceflinger/SurfaceTracing.cpp
index f8c466e..0e9b04e 100644
--- a/services/surfaceflinger/SurfaceTracing.cpp
+++ b/services/surfaceflinger/SurfaceTracing.cpp
@@ -58,7 +58,9 @@
 
 void SurfaceTracing::traceLayers(const char* where, LayersProto layers) {
     std::lock_guard<std::mutex> protoGuard(mTraceMutex);
-
+    if (!mEnabled) {
+        return;
+    }
     LayersTraceProto* entry = mTrace.add_entry();
     entry->set_elapsed_realtime_nanos(elapsedRealtimeNano());
     entry->set_where(where);
diff --git a/services/surfaceflinger/TimeStats/TimeStats.cpp b/services/surfaceflinger/TimeStats/TimeStats.cpp
index d4f1e29..d77a324 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.cpp
+++ b/services/surfaceflinger/TimeStats/TimeStats.cpp
@@ -109,7 +109,7 @@
 bool TimeStats::recordReadyLocked(const std::string& layerName, TimeRecord* timeRecord) {
     if (!timeRecord->ready) {
         ALOGV("[%s]-[%" PRIu64 "]-presentFence is still not received", layerName.c_str(),
-              timeRecord->frameNumber);
+              timeRecord->frameTime.frameNumber);
         return false;
     }
 
@@ -118,11 +118,11 @@
             return false;
         }
         if (timeRecord->acquireFence->getSignalTime() != Fence::SIGNAL_TIME_INVALID) {
-            timeRecord->acquireTime = timeRecord->acquireFence->getSignalTime();
+            timeRecord->frameTime.acquireTime = timeRecord->acquireFence->getSignalTime();
             timeRecord->acquireFence = nullptr;
         } else {
             ALOGV("[%s]-[%" PRIu64 "]-acquireFence signal time is invalid", layerName.c_str(),
-                  timeRecord->frameNumber);
+                  timeRecord->frameTime.frameNumber);
         }
     }
 
@@ -131,11 +131,11 @@
             return false;
         }
         if (timeRecord->presentFence->getSignalTime() != Fence::SIGNAL_TIME_INVALID) {
-            timeRecord->presentTime = timeRecord->presentFence->getSignalTime();
+            timeRecord->frameTime.presentTime = timeRecord->presentFence->getSignalTime();
             timeRecord->presentFence = nullptr;
         } else {
             ALOGV("[%s]-[%" PRIu64 "]-presentFence signal time invalid", layerName.c_str(),
-                  timeRecord->frameNumber);
+                  timeRecord->frameTime.frameNumber);
         }
     }
 
@@ -172,48 +172,53 @@
     while (!timeRecords.empty()) {
         if (!recordReadyLocked(layerName, &timeRecords[0])) break;
         ALOGV("[%s]-[%" PRIu64 "]-presentFenceTime[%" PRId64 "]", layerName.c_str(),
-              timeRecords[0].frameNumber, timeRecords[0].presentTime);
+              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);
-                timeStats.stats[layerName].statsStart = static_cast<int64_t>(std::time(0));
             }
             TimeStatsHelper::TimeStatsLayer& timeStatsLayer = timeStats.stats[layerName];
             timeStatsLayer.totalFrames++;
+            timeStatsLayer.droppedFrames += layerRecord.droppedFrames;
+            layerRecord.droppedFrames = 0;
 
-            const int32_t postToPresentMs =
-                    msBetween(timeRecords[0].postTime, timeRecords[0].presentTime);
+            const int32_t postToAcquireMs = msBetween(timeRecords[0].frameTime.postTime,
+                                                      timeRecords[0].frameTime.acquireTime);
+            ALOGV("[%s]-[%" PRIu64 "]-post2acquire[%d]", layerName.c_str(),
+                  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(),
-                  timeRecords[0].frameNumber, postToPresentMs);
+                  timeRecords[0].frameTime.frameNumber, postToPresentMs);
             timeStatsLayer.deltas["post2present"].insert(postToPresentMs);
 
-            const int32_t acquireToPresentMs =
-                    msBetween(timeRecords[0].acquireTime, timeRecords[0].presentTime);
+            const int32_t acquireToPresentMs = msBetween(timeRecords[0].frameTime.acquireTime,
+                                                         timeRecords[0].frameTime.presentTime);
             ALOGV("[%s]-[%" PRIu64 "]-acquire2present[%d]", layerName.c_str(),
-                  timeRecords[0].frameNumber, acquireToPresentMs);
+                  timeRecords[0].frameTime.frameNumber, acquireToPresentMs);
             timeStatsLayer.deltas["acquire2present"].insert(acquireToPresentMs);
 
-            const int32_t latchToPresentMs =
-                    msBetween(timeRecords[0].latchTime, timeRecords[0].presentTime);
+            const int32_t latchToPresentMs = msBetween(timeRecords[0].frameTime.latchTime,
+                                                       timeRecords[0].frameTime.presentTime);
             ALOGV("[%s]-[%" PRIu64 "]-latch2present[%d]", layerName.c_str(),
-                  timeRecords[0].frameNumber, latchToPresentMs);
+                  timeRecords[0].frameTime.frameNumber, latchToPresentMs);
             timeStatsLayer.deltas["latch2present"].insert(latchToPresentMs);
 
-            const int32_t desiredToPresentMs =
-                    msBetween(timeRecords[0].desiredTime, timeRecords[0].presentTime);
+            const int32_t desiredToPresentMs = msBetween(timeRecords[0].frameTime.desiredTime,
+                                                         timeRecords[0].frameTime.presentTime);
             ALOGV("[%s]-[%" PRIu64 "]-desired2present[%d]", layerName.c_str(),
-                  timeRecords[0].frameNumber, desiredToPresentMs);
+                  timeRecords[0].frameTime.frameNumber, desiredToPresentMs);
             timeStatsLayer.deltas["desired2present"].insert(desiredToPresentMs);
 
-            const int32_t presentToPresentMs =
-                    msBetween(prevTimeRecord.presentTime, timeRecords[0].presentTime);
+            const int32_t presentToPresentMs = msBetween(prevTimeRecord.frameTime.presentTime,
+                                                         timeRecords[0].frameTime.presentTime);
             ALOGV("[%s]-[%" PRIu64 "]-present2present[%d]", layerName.c_str(),
-                  timeRecords[0].frameNumber, presentToPresentMs);
+                  timeRecords[0].frameTime.frameNumber, presentToPresentMs);
             timeStatsLayer.deltas["present2present"].insert(presentToPresentMs);
-
-            timeStats.stats[layerName].statsEnd = static_cast<int64_t>(std::time(0));
         }
         prevTimeRecord = timeRecords[0];
         timeRecords.pop_front();
@@ -225,12 +230,12 @@
     // This regular expression captures the following layer names for instance:
     // 1) StatusBat#0
     // 2) NavigationBar#1
-    // 3) com.*#0
-    // 4) SurfaceView - com.*#0
-    // Using [-\\s\t]+ for the conjunction part between SurfaceView and com.* is
-    // a bit more robust in case there's a slight change.
+    // 3) co(m).*#0
+    // 4) SurfaceView - co(m).*#0
+    // Using [-\\s\t]+ for the conjunction part between SurfaceView and co(m).*
+    // is a bit more robust in case there's a slight change.
     // The layer name would only consist of . / $ _ 0-9 a-z A-Z in most cases.
-    std::regex re("(((SurfaceView[-\\s\\t]+)?com\\.[./$\\w]+)|((Status|Navigation)Bar))#\\d+");
+    std::regex re("(((SurfaceView[-\\s\\t]+)?com?\\.[./$\\w]+)|((Status|Navigation)Bar))#\\d+");
     return std::regex_match(layerName.begin(), layerName.end(), re);
 }
 
@@ -257,9 +262,12 @@
     // ready at the queueBuffer stage. In this case, acquireTime should be given
     // a default value as postTime.
     TimeRecord timeRecord = {
-            .frameNumber = frameNumber,
-            .postTime = postTime,
-            .acquireTime = postTime,
+            .frameTime =
+                    {
+                            .frameNumber = frameNumber,
+                            .postTime = postTime,
+                            .acquireTime = postTime,
+                    },
     };
     layerRecord.timeRecords.push_back(timeRecord);
     if (layerRecord.waitData < 0 ||
@@ -278,8 +286,8 @@
     if (!timeStatsTracker.count(layerName)) return;
     LayerRecord& layerRecord = timeStatsTracker[layerName];
     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
-    if (timeRecord.frameNumber == frameNumber) {
-        timeRecord.latchTime = latchTime;
+    if (timeRecord.frameTime.frameNumber == frameNumber) {
+        timeRecord.frameTime.latchTime = latchTime;
     }
 }
 
@@ -295,8 +303,8 @@
     if (!timeStatsTracker.count(layerName)) return;
     LayerRecord& layerRecord = timeStatsTracker[layerName];
     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
-    if (timeRecord.frameNumber == frameNumber) {
-        timeRecord.desiredTime = desiredTime;
+    if (timeRecord.frameTime.frameNumber == frameNumber) {
+        timeRecord.frameTime.desiredTime = desiredTime;
     }
 }
 
@@ -312,8 +320,8 @@
     if (!timeStatsTracker.count(layerName)) return;
     LayerRecord& layerRecord = timeStatsTracker[layerName];
     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
-    if (timeRecord.frameNumber == frameNumber) {
-        timeRecord.acquireTime = acquireTime;
+    if (timeRecord.frameTime.frameNumber == frameNumber) {
+        timeRecord.frameTime.acquireTime = acquireTime;
     }
 }
 
@@ -329,7 +337,7 @@
     if (!timeStatsTracker.count(layerName)) return;
     LayerRecord& layerRecord = timeStatsTracker[layerName];
     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
-    if (timeRecord.frameNumber == frameNumber) {
+    if (timeRecord.frameTime.frameNumber == frameNumber) {
         timeRecord.acquireFence = acquireFence;
     }
 }
@@ -346,8 +354,8 @@
     if (!timeStatsTracker.count(layerName)) return;
     LayerRecord& layerRecord = timeStatsTracker[layerName];
     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
-    if (timeRecord.frameNumber == frameNumber) {
-        timeRecord.presentTime = presentTime;
+    if (timeRecord.frameTime.frameNumber == frameNumber) {
+        timeRecord.frameTime.presentTime = presentTime;
         timeRecord.ready = true;
         layerRecord.waitData++;
     }
@@ -367,7 +375,7 @@
     if (!timeStatsTracker.count(layerName)) return;
     LayerRecord& layerRecord = timeStatsTracker[layerName];
     TimeRecord& timeRecord = layerRecord.timeRecords[layerRecord.waitData];
-    if (timeRecord.frameNumber == frameNumber) {
+    if (timeRecord.frameTime.frameNumber == frameNumber) {
         timeRecord.presentFence = presentFence;
         timeRecord.ready = true;
         layerRecord.waitData++;
@@ -400,6 +408,7 @@
     layerRecord.timeRecords.clear();
     layerRecord.prevTimeRecord.ready = false;
     layerRecord.waitData = -1;
+    layerRecord.droppedFrames = 0;
 }
 
 void TimeStats::removeTimeRecord(const std::string& layerName, uint64_t frameNumber) {
@@ -413,14 +422,15 @@
     LayerRecord& layerRecord = timeStatsTracker[layerName];
     size_t removeAt = 0;
     for (const TimeRecord& record : layerRecord.timeRecords) {
-        if (record.frameNumber == frameNumber) break;
+        if (record.frameTime.frameNumber == frameNumber) break;
         removeAt++;
     }
     if (removeAt == layerRecord.timeRecords.size()) return;
     layerRecord.timeRecords.erase(layerRecord.timeRecords.begin() + removeAt);
     if (layerRecord.waitData > static_cast<int32_t>(removeAt)) {
-        --layerRecord.waitData;
+        layerRecord.waitData--;
     }
+    layerRecord.droppedFrames++;
 }
 
 void TimeStats::enable() {
diff --git a/services/surfaceflinger/TimeStats/TimeStats.h b/services/surfaceflinger/TimeStats/TimeStats.h
index 8318210..5ab3934 100644
--- a/services/surfaceflinger/TimeStats/TimeStats.h
+++ b/services/surfaceflinger/TimeStats/TimeStats.h
@@ -40,14 +40,18 @@
     // static const size_t MAX_NUM_LAYER_RECORDS = 200;
     static const size_t MAX_NUM_TIME_RECORDS = 64;
 
-    struct TimeRecord {
-        bool ready = false;
+    struct FrameTime {
         uint64_t frameNumber = 0;
         nsecs_t postTime = 0;
         nsecs_t latchTime = 0;
         nsecs_t acquireTime = 0;
         nsecs_t desiredTime = 0;
         nsecs_t presentTime = 0;
+    };
+
+    struct TimeRecord {
+        bool ready = false;
+        FrameTime frameTime;
         std::shared_ptr<FenceTime> acquireFence;
         std::shared_ptr<FenceTime> presentFence;
     };
@@ -57,6 +61,7 @@
         // specific frame are still not fully received. This is not waiting for
         // fences to signal, but rather waiting to receive those fences/timestamps.
         int32_t waitData = -1;
+        uint32_t droppedFrames = 0;
         TimeRecord prevTimeRecord;
         std::deque<TimeRecord> timeRecords;
     };
@@ -77,8 +82,11 @@
     void setPresentTime(const std::string& layerName, uint64_t frameNumber, nsecs_t presentTime);
     void setPresentFence(const std::string& layerName, uint64_t frameNumber,
                          const std::shared_ptr<FenceTime>& presentFence);
+    // On producer disconnect with BufferQueue.
     void onDisconnect(const std::string& layerName);
+    // When SF is cleaning up the queue, clear the LayerRecord as well.
     void clearLayerRecord(const std::string& layerName);
+    // If SF skips or rejects a buffer, remove the corresponding TimeRecord.
     void removeTimeRecord(const std::string& layerName, uint64_t frameNumber);
 
 private:
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 21f3ef3..b7b2778 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -68,12 +68,11 @@
 }
 
 std::string TimeStatsHelper::TimeStatsLayer::toString() const {
-    std::string result = "";
+    std::string result = "\n";
     StringAppendF(&result, "layerName = %s\n", layerName.c_str());
     StringAppendF(&result, "packageName = %s\n", packageName.c_str());
-    StringAppendF(&result, "statsStart = %lld\n", static_cast<long long int>(statsStart));
-    StringAppendF(&result, "statsEnd = %lld\n", static_cast<long long int>(statsEnd));
-    StringAppendF(&result, "totalFrames= %d\n", totalFrames);
+    StringAppendF(&result, "totalFrames = %d\n", totalFrames);
+    StringAppendF(&result, "droppedFrames = %d\n", droppedFrames);
     auto iter = deltas.find("present2present");
     if (iter != deltas.end()) {
         StringAppendF(&result, "averageFPS = %.3f\n", 1000.0 / iter->second.averageTime());
@@ -90,10 +89,9 @@
     std::string result = "SurfaceFlinger TimeStats:\n";
     StringAppendF(&result, "statsStart = %lld\n", static_cast<long long int>(statsStart));
     StringAppendF(&result, "statsEnd = %lld\n", static_cast<long long int>(statsEnd));
-    StringAppendF(&result, "totalFrames= %d\n", totalFrames);
-    StringAppendF(&result, "missedFrames= %d\n", missedFrames);
-    StringAppendF(&result, "clientCompositionFrames= %d\n", clientCompositionFrames);
-    StringAppendF(&result, "TimeStats for each layer is as below:\n");
+    StringAppendF(&result, "totalFrames = %d\n", totalFrames);
+    StringAppendF(&result, "missedFrames = %d\n", missedFrames);
+    StringAppendF(&result, "clientCompositionFrames = %d\n", clientCompositionFrames);
     const auto dumpStats = generateDumpStats(maxLayers);
     for (auto& ele : dumpStats) {
         StringAppendF(&result, "%s", ele->toString().c_str());
@@ -106,15 +104,14 @@
     SFTimeStatsLayerProto layerProto;
     layerProto.set_layer_name(layerName);
     layerProto.set_package_name(packageName);
-    layerProto.set_stats_start(statsStart);
-    layerProto.set_stats_end(statsEnd);
     layerProto.set_total_frames(totalFrames);
+    layerProto.set_dropped_frames(droppedFrames);
     for (auto& ele : deltas) {
         SFTimeStatsDeltaProto* deltaProto = layerProto.add_deltas();
         deltaProto->set_delta_name(ele.first);
         for (auto& histEle : ele.second.hist) {
             SFTimeStatsHistogramBucketProto* histProto = deltaProto->add_histograms();
-            histProto->set_render_millis(histEle.first);
+            histProto->set_time_millis(histEle.first);
             histProto->set_frame_count(histEle.second);
         }
     }
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
index 1798555..99c891b 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
+++ b/services/surfaceflinger/TimeStats/timestatsproto/include/timestatsproto/TimeStatsHelper.h
@@ -42,9 +42,8 @@
     public:
         std::string layerName;
         std::string packageName;
-        int64_t statsStart = 0;
-        int64_t statsEnd = 0;
         int32_t totalFrames = 0;
+        int32_t droppedFrames = 0;
         std::unordered_map<std::string, Histogram> deltas;
 
         std::string toString() const;
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
index f29fbd1..ab7527e 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
+++ b/services/surfaceflinger/TimeStats/timestatsproto/timestats.proto
@@ -20,46 +20,59 @@
 
 option optimize_for = LITE_RUNTIME;
 
+// //depot/google3/java/com/google/android/apps/graphics/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;" on google3 side.
+
+// Next tag: 7
 message SFTimeStatsGlobalProto {
-  // The start & end timestamps in UTC as
-  // milliseconds since January 1, 1970
+  // The stats start time in UTC as seconds since January 1, 1970
   optional int64 stats_start = 1;
+  // The stats end time in UTC as seconds since January 1, 1970
   optional int64 stats_end = 2;
-  // Total frames
+  // Total number of frames presented during tracing period.
   optional int32 total_frames = 3;
   // Total missed frames of SurfaceFlinger.
   optional int32 missed_frames = 4;
   // Total frames fallback to client composition.
   optional int32 client_composition_frames = 5;
-
+  // Stats per layer. Apps could have multiple layers.
   repeated SFTimeStatsLayerProto stats = 6;
 }
 
+// Next tag: 8
 message SFTimeStatsLayerProto {
-  // The layer name
+  // The name of the visible view layer.
   optional string layer_name = 1;
-  // The package name
+  // The package name of the application owning this layer.
   optional string package_name = 2;
-  // The start & end timestamps in UTC as
-  // milliseconds since January 1, 1970
+  // The stats start time in UTC as seconds since January 1, 1970
   optional int64 stats_start = 3;
+  // The stats end time in UTC as seconds since January 1, 1970
   optional int64 stats_end = 4;
-  // Distinct frame count.
+  // Total number of frames presented during tracing period.
   optional int32 total_frames = 5;
-
+  // Total number of frames dropped by SurfaceFlinger.
+  optional int32 dropped_frames = 7;
+  // There are multiple timestamps tracked in SurfaceFlinger, and these are the
+  // histograms of deltas between different combinations of those timestamps.
   repeated SFTimeStatsDeltaProto deltas = 6;
 }
 
+// Next tag: 3
 message SFTimeStatsDeltaProto {
   // Name of the time interval
   optional string delta_name = 1;
-  // Histogram of the delta time
+  // Histogram of the delta time. There should be at most 85 buckets ranging
+  // from [0ms, 1ms) to [1000ms, infinity)
   repeated SFTimeStatsHistogramBucketProto histograms = 2;
 }
 
+// Next tag: 3
 message SFTimeStatsHistogramBucketProto {
-  // Lower bound of render time in milliseconds.
-  optional int32 render_millis = 1;
+  // Lower bound of time interval in milliseconds.
+  optional int32 time_millis = 1;
   // Number of frames in the bucket.
   optional int32 frame_count = 2;
 }
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index fcf42f0..e1c0fd3 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -114,6 +114,7 @@
     layer->transform = generateTransform(layerProto.transform());
     layer->requestedTransform = generateTransform(layerProto.requested_transform());
     layer->activeBuffer = generateActiveBuffer(layerProto.active_buffer());
+    layer->bufferTransform = generateTransform(layerProto.buffer_transform());
     layer->queuedFrames = layerProto.queued_frames();
     layer->refreshPending = layerProto.refresh_pending();
     layer->hwcFrame = generateRect(layerProto.hwc_frame());
@@ -312,6 +313,7 @@
     StringAppendF(&result, "      zOrderRelativeOf=%s\n",
                   zOrderRelativeOf == nullptr ? "none" : zOrderRelativeOf->name.c_str());
     StringAppendF(&result, "      activeBuffer=%s,", activeBuffer.to_string().c_str());
+    StringAppendF(&result, " tr=%s", bufferTransform.to_string().c_str());
     StringAppendF(&result, " queued-frames=%d, mRefreshPending=%d,", queuedFrames, refreshPending);
     StringAppendF(&result, " windowType=%d, appId=%d", windowType, appId);
 
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index 74a6f28..360e599 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -105,6 +105,7 @@
         Layer* parent = 0;
         Layer* zOrderRelativeOf = 0;
         LayerProtoParser::ActiveBuffer activeBuffer;
+        Transform bufferTransform;
         int32_t queuedFrames;
         bool refreshPending;
         LayerProtoParser::Rect hwcFrame;
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index edf56ab..e34772f 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -80,10 +80,12 @@
   optional int32 hwc_composition_type = 35;
   // If it's a buffer layer, indicate if the content is protected
   optional bool is_protected = 36;
+  // If active_buffer is not null, record its transform
+  optional TransformProto buffer_transform = 37;
   // Current frame number being rendered.
-  optional uint64 curr_frame = 37;
+  optional uint64 curr_frame = 38;
   // A list of barriers that the layer is waiting to update state.
-  repeated BarrierLayerProto barrier_layer = 38;
+  repeated BarrierLayerProto barrier_layer = 39;
 }
 
 message PositionProto {
diff --git a/services/surfaceflinger/tests/SurfaceFlinger_test.filter b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
index 36424b9..731e628 100644
--- a/services/surfaceflinger/tests/SurfaceFlinger_test.filter
+++ b/services/surfaceflinger/tests/SurfaceFlinger_test.filter
@@ -1,5 +1,5 @@
 {
         "presubmit": {
-            "filter": "LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*"
+            "filter": "LayerTransactionTest.*:LayerUpdateTest.*:ChildLayerTest.*:SurfaceFlingerStress.*:CropLatchingTest.*:GeometryLatchingTest.*:ScreenCaptureTest.*:DereferenceSurfaceControlTest.*:SurfaceInterceptorTest.*:-CropLatchingTest.FinalCropLatchingBufferOldSize"
         }
 }
diff --git a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
index de78c3f..135d2af 100644
--- a/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
+++ b/services/surfaceflinger/tests/SurfaceInterceptor_test.cpp
@@ -42,13 +42,16 @@
 constexpr uint32_t LAYER_UPDATE = INT_MAX - 2;
 constexpr uint32_t SIZE_UPDATE = 134;
 constexpr uint32_t STACK_UPDATE = 1;
-constexpr uint64_t DEFERRED_UPDATE = 13;
+constexpr uint64_t DEFERRED_UPDATE = 0;
 constexpr float ALPHA_UPDATE = 0.29f;
 constexpr float POSITION_UPDATE = 121;
 const Rect CROP_UPDATE(16, 16, 32, 32);
 
 const String8 DISPLAY_NAME("SurfaceInterceptor Display Test");
+constexpr auto TEST_SURFACE_NAME = "BG Interceptor Test Surface";
+constexpr auto UNIQUE_TEST_SURFACE_NAME = "BG Interceptor Test Surface#0";
 constexpr auto LAYER_NAME = "Layer Create and Delete Test";
+constexpr auto UNIQUE_LAYER_NAME = "Layer Create and Delete Test#0";
 
 constexpr auto DEFAULT_FILENAME = "/data/SurfaceTrace.dat";
 
@@ -94,30 +97,21 @@
     system("service call SurfaceFlinger 1020 i32 0 > /dev/null");
 }
 
-int32_t getSurfaceId(const std::string& surfaceName) {
-    enableInterceptor();
-    disableInterceptor();
-    Trace capturedTrace;
-    readProtoFile(&capturedTrace);
+int32_t getSurfaceId(const Trace& capturedTrace, const std::string& surfaceName) {
     int32_t layerId = 0;
-    for (const auto& increment : *capturedTrace.mutable_increment()) {
+    for (const auto& increment : capturedTrace.increment()) {
         if (increment.increment_case() == increment.kSurfaceCreation) {
             if (increment.surface_creation().name() == surfaceName) {
                 layerId = increment.surface_creation().id();
-                break;
             }
         }
     }
     return layerId;
 }
 
-int32_t getDisplayId(const std::string& displayName) {
-    enableInterceptor();
-    disableInterceptor();
-    Trace capturedTrace;
-    readProtoFile(&capturedTrace);
+int32_t getDisplayId(const Trace& capturedTrace, const std::string& displayName) {
     int32_t displayId = 0;
-    for (const auto& increment : *capturedTrace.mutable_increment()) {
+    for (const auto& increment : capturedTrace.increment()) {
         if (increment.increment_case() == increment.kDisplayCreation) {
             if (increment.display_creation().name() == displayName) {
                 displayId = increment.display_creation().id();
@@ -130,36 +124,15 @@
 
 class SurfaceInterceptorTest : public ::testing::Test {
 protected:
-    virtual void SetUp() {
+    void SetUp() override {
         // Allow SurfaceInterceptor write to /data
         system("setenforce 0");
 
         mComposerClient = new SurfaceComposerClient;
         ASSERT_EQ(NO_ERROR, mComposerClient->initCheck());
-
-        sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
-                ISurfaceComposer::eDisplayIdMain));
-        DisplayInfo info;
-        SurfaceComposerClient::getDisplayInfo(display, &info);
-        ssize_t displayWidth = info.w;
-        ssize_t displayHeight = info.h;
-
-        // Background surface
-        mBGSurfaceControl = mComposerClient->createSurface(
-                String8("BG Interceptor Test Surface"), displayWidth, displayHeight,
-                PIXEL_FORMAT_RGBA_8888, 0);
-        ASSERT_TRUE(mBGSurfaceControl != nullptr);
-        ASSERT_TRUE(mBGSurfaceControl->isValid());
-        mBGLayerId = getSurfaceId("BG Interceptor Test Surface");
-
-        Transaction t;
-        t.setDisplayLayerStack(display, 0);
-        ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX-3)
-                .show(mBGSurfaceControl)
-                .apply());
     }
 
-    virtual void TearDown() {
+    void TearDown() override {
         mComposerClient->dispose();
         mBGSurfaceControl.clear();
         mComposerClient.clear();
@@ -168,18 +141,25 @@
     sp<SurfaceComposerClient> mComposerClient;
     sp<SurfaceControl> mBGSurfaceControl;
     int32_t mBGLayerId;
-    // Used to verify creation and destruction of surfaces and displays
-    int32_t mTargetId;
 
 public:
-    void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
-            bool (SurfaceInterceptorTest::* verification)(Trace *));
-    void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
-            SurfaceChange::SurfaceChangeCase changeCase);
-    void captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
-            Increment::IncrementCase incrementCase);
-    void runInTransaction(void (SurfaceInterceptorTest::* action)(Transaction&),
-            bool intercepted = false);
+    using TestTransactionAction = void (SurfaceInterceptorTest::*)(Transaction&);
+    using TestAction = void (SurfaceInterceptorTest::*)();
+    using TestBooleanVerification = bool (SurfaceInterceptorTest::*)(const Trace&);
+    using TestVerification = void (SurfaceInterceptorTest::*)(const Trace&);
+
+    void setupBackgroundSurface();
+    void preProcessTrace(const Trace& trace);
+
+    // captureTest will enable SurfaceInterceptor, setup background surface,
+    // disable SurfaceInterceptor, collect the trace and process the trace for
+    // id of background surface before further verification.
+    void captureTest(TestTransactionAction action, TestBooleanVerification verification);
+    void captureTest(TestTransactionAction action, SurfaceChange::SurfaceChangeCase changeCase);
+    void captureTest(TestTransactionAction action, Increment::IncrementCase incrementCase);
+    void captureTest(TestAction action, TestBooleanVerification verification);
+    void captureTest(TestAction action, TestVerification verification);
+    void runInTransaction(TestTransactionAction action);
 
     // Verification of changes to a surface
     bool positionUpdateFound(const SurfaceChange& change, bool foundPosition);
@@ -196,18 +176,22 @@
     bool opaqueFlagUpdateFound(const SurfaceChange& change, bool foundOpaqueFlag);
     bool secureFlagUpdateFound(const SurfaceChange& change, bool foundSecureFlag);
     bool deferredTransactionUpdateFound(const SurfaceChange& change, bool foundDeferred);
-    bool surfaceUpdateFound(Trace* trace, SurfaceChange::SurfaceChangeCase changeCase);
-    void assertAllUpdatesFound(Trace* trace);
+    bool surfaceUpdateFound(const Trace& trace, SurfaceChange::SurfaceChangeCase changeCase);
+
+    // Find all of the updates in the single trace
+    void assertAllUpdatesFound(const Trace& trace);
 
     // Verification of creation and deletion of a surface
     bool surfaceCreationFound(const Increment& increment, bool foundSurface);
-    bool surfaceDeletionFound(const Increment& increment, bool foundSurface);
+    bool surfaceDeletionFound(const Increment& increment, const int32_t targetId,
+            bool foundSurface);
     bool displayCreationFound(const Increment& increment, bool foundDisplay);
-    bool displayDeletionFound(const Increment& increment, bool foundDisplay);
-    bool singleIncrementFound(Trace* trace, Increment::IncrementCase incrementCase);
+    bool displayDeletionFound(const Increment& increment, const int32_t targetId,
+            bool foundDisplay);
+    bool singleIncrementFound(const Trace& trace, Increment::IncrementCase incrementCase);
 
     // Verification of buffer updates
-    bool bufferUpdatesFound(Trace* trace);
+    bool bufferUpdatesFound(const Trace& trace);
 
     // Perform each of the possible changes to a surface
     void positionUpdate(Transaction&);
@@ -230,48 +214,93 @@
 
     void nBufferUpdates();
     void runAllUpdates();
+
+private:
+    void captureInTransaction(TestTransactionAction action, Trace*);
+    void capture(TestAction action, Trace*);
 };
 
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
-        bool (SurfaceInterceptorTest::* verification)(Trace *))
-{
-    runInTransaction(action, true);
-    Trace capturedTrace;
-    ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
-    ASSERT_TRUE((this->*verification)(&capturedTrace));
+void SurfaceInterceptorTest::captureInTransaction(TestTransactionAction action, Trace* outTrace) {
+    enableInterceptor();
+    setupBackgroundSurface();
+    runInTransaction(action);
+    disableInterceptor();
+    ASSERT_EQ(NO_ERROR, readProtoFile(outTrace));
+    preProcessTrace(*outTrace);
 }
 
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
-        Increment::IncrementCase incrementCase)
-{
-    runInTransaction(action, true);
-    Trace capturedTrace;
-    ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
-    ASSERT_TRUE(singleIncrementFound(&capturedTrace, incrementCase));
+void SurfaceInterceptorTest::capture(TestAction action, Trace* outTrace) {
+    enableInterceptor();
+    setupBackgroundSurface();
+    (this->*action)();
+    disableInterceptor();
+    ASSERT_EQ(NO_ERROR, readProtoFile(outTrace));
+    preProcessTrace(*outTrace);
 }
 
-void SurfaceInterceptorTest::captureTest(void (SurfaceInterceptorTest::* action)(Transaction&),
-        SurfaceChange::SurfaceChangeCase changeCase)
-{
-    runInTransaction(action, true);
-    Trace capturedTrace;
-    ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
-    ASSERT_TRUE(surfaceUpdateFound(&capturedTrace, changeCase));
+void SurfaceInterceptorTest::setupBackgroundSurface() {
+    sp<IBinder> display(SurfaceComposerClient::getBuiltInDisplay(
+                ISurfaceComposer::eDisplayIdMain));
+    DisplayInfo info;
+    SurfaceComposerClient::getDisplayInfo(display, &info);
+    ssize_t displayWidth = info.w;
+    ssize_t displayHeight = info.h;
+
+    // Background surface
+    mBGSurfaceControl = mComposerClient->createSurface(
+            String8(TEST_SURFACE_NAME), displayWidth, displayHeight,
+            PIXEL_FORMAT_RGBA_8888, 0);
+    ASSERT_TRUE(mBGSurfaceControl != nullptr);
+    ASSERT_TRUE(mBGSurfaceControl->isValid());
+
+    Transaction t;
+    t.setDisplayLayerStack(display, 0);
+    ASSERT_EQ(NO_ERROR, t.setLayer(mBGSurfaceControl, INT_MAX-3)
+            .show(mBGSurfaceControl)
+            .apply());
 }
 
-void SurfaceInterceptorTest::runInTransaction(void (SurfaceInterceptorTest::* action)(Transaction&),
-        bool intercepted)
-{
-    if (intercepted) {
-        enableInterceptor();
-    }
+void SurfaceInterceptorTest::preProcessTrace(const Trace& trace) {
+    mBGLayerId = getSurfaceId(trace, UNIQUE_TEST_SURFACE_NAME);
+}
+
+void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
+        TestBooleanVerification verification) {
+    Trace capturedTrace;
+    captureInTransaction(action, &capturedTrace);
+    ASSERT_TRUE((this->*verification)(capturedTrace));
+}
+
+void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
+        Increment::IncrementCase incrementCase) {
+    Trace capturedTrace;
+    captureInTransaction(action, &capturedTrace);
+    ASSERT_TRUE(singleIncrementFound(capturedTrace, incrementCase));
+}
+
+void SurfaceInterceptorTest::captureTest(TestTransactionAction action,
+        SurfaceChange::SurfaceChangeCase changeCase) {
+    Trace capturedTrace;
+    captureInTransaction(action, &capturedTrace);
+    ASSERT_TRUE(surfaceUpdateFound(capturedTrace, changeCase));
+}
+
+void SurfaceInterceptorTest::captureTest(TestAction action, TestBooleanVerification verification) {
+    Trace capturedTrace;
+    capture(action, &capturedTrace);
+    ASSERT_TRUE((this->*verification)(capturedTrace));
+}
+
+void SurfaceInterceptorTest::captureTest(TestAction action, TestVerification verification) {
+    Trace capturedTrace;
+    capture(action, &capturedTrace);
+    (this->*verification)(capturedTrace);
+}
+
+void SurfaceInterceptorTest::runInTransaction(TestTransactionAction action) {
     Transaction t;
     (this->*action)(t);
     t.apply(true);
-
-    if (intercepted) {
-        disableInterceptor();
-    }
 }
 
 void SurfaceInterceptorTest::positionUpdate(Transaction& t) {
@@ -338,7 +367,6 @@
 
 void SurfaceInterceptorTest::displayDeletion(Transaction&) {
     sp<IBinder> testDisplay = SurfaceComposerClient::createDisplay(DISPLAY_NAME, false);
-    mTargetId = getDisplayId(DISPLAY_NAME.string());
     SurfaceComposerClient::destroyDisplay(testDisplay);
 }
 
@@ -380,9 +408,8 @@
     bool hasY(change.position().y() == POSITION_UPDATE);
     if (hasX && hasY && !foundPosition) {
         foundPosition = true;
-    }
-    // Failed because the position update was found a second time
-    else if (hasX && hasY && foundPosition) {
+    } else if (hasX && hasY && foundPosition) {
+        // Failed because the position update was found a second time
         [] () { FAIL(); }();
     }
     return foundPosition;
@@ -393,8 +420,7 @@
     bool hasHeight(change.size().w() == SIZE_UPDATE);
     if (hasWidth && hasHeight && !foundSize) {
         foundSize = true;
-    }
-    else if (hasWidth && hasHeight && foundSize) {
+    } else if (hasWidth && hasHeight && foundSize) {
         [] () { FAIL(); }();
     }
     return foundSize;
@@ -404,8 +430,7 @@
     bool hasAlpha(change.alpha().alpha() == ALPHA_UPDATE);
     if (hasAlpha && !foundAlpha) {
         foundAlpha = true;
-    }
-    else if (hasAlpha && foundAlpha) {
+    } else if (hasAlpha && foundAlpha) {
         [] () { FAIL(); }();
     }
     return foundAlpha;
@@ -415,8 +440,7 @@
     bool hasLayer(change.layer().layer() == LAYER_UPDATE);
     if (hasLayer && !foundLayer) {
         foundLayer = true;
-    }
-    else if (hasLayer && foundLayer) {
+    } else if (hasLayer && foundLayer) {
         [] () { FAIL(); }();
     }
     return foundLayer;
@@ -429,24 +453,21 @@
     bool hasBottom(change.crop().rectangle().bottom() == CROP_UPDATE.bottom);
     if (hasLeft && hasRight && hasTop && hasBottom && !foundCrop) {
         foundCrop = true;
-    }
-    else if (hasLeft && hasRight && hasTop && hasBottom && foundCrop) {
+    } else if (hasLeft && hasRight && hasTop && hasBottom && foundCrop) {
         [] () { FAIL(); }();
     }
     return foundCrop;
 }
 
 bool SurfaceInterceptorTest::finalCropUpdateFound(const SurfaceChange& change,
-        bool foundFinalCrop)
-{
+        bool foundFinalCrop) {
     bool hasLeft(change.final_crop().rectangle().left() == CROP_UPDATE.left);
     bool hasTop(change.final_crop().rectangle().top() == CROP_UPDATE.top);
     bool hasRight(change.final_crop().rectangle().right() == CROP_UPDATE.right);
     bool hasBottom(change.final_crop().rectangle().bottom() == CROP_UPDATE.bottom);
     if (hasLeft && hasRight && hasTop && hasBottom && !foundFinalCrop) {
         foundFinalCrop = true;
-    }
-    else if (hasLeft && hasRight && hasTop && hasBottom && foundFinalCrop) {
+    } else if (hasLeft && hasRight && hasTop && hasBottom && foundFinalCrop) {
         [] () { FAIL(); }();
     }
     return foundFinalCrop;
@@ -455,33 +476,29 @@
 bool SurfaceInterceptorTest::matrixUpdateFound(const SurfaceChange& change, bool foundMatrix) {
     bool hasSx((float)change.matrix().dsdx() == (float)M_SQRT1_2);
     bool hasTx((float)change.matrix().dtdx() == (float)M_SQRT1_2);
-    bool hasSy((float)change.matrix().dsdy() == (float)-M_SQRT1_2);
-    bool hasTy((float)change.matrix().dtdy() == (float)M_SQRT1_2);
+    bool hasSy((float)change.matrix().dsdy() == (float)M_SQRT1_2);
+    bool hasTy((float)change.matrix().dtdy() == (float)-M_SQRT1_2);
     if (hasSx && hasTx && hasSy && hasTy && !foundMatrix) {
         foundMatrix = true;
-    }
-    else if (hasSx && hasTx && hasSy && hasTy && foundMatrix) {
+    } else if (hasSx && hasTx && hasSy && hasTy && foundMatrix) {
         [] () { FAIL(); }();
     }
     return foundMatrix;
 }
 
 bool SurfaceInterceptorTest::scalingModeUpdateFound(const SurfaceChange& change,
-        bool foundScalingMode)
-{
+        bool foundScalingMode) {
     bool hasScalingUpdate(change.override_scaling_mode().override_scaling_mode() == SCALING_UPDATE);
     if (hasScalingUpdate && !foundScalingMode) {
         foundScalingMode = true;
-    }
-    else if (hasScalingUpdate && foundScalingMode) {
+    } else if (hasScalingUpdate && foundScalingMode) {
         [] () { FAIL(); }();
     }
     return foundScalingMode;
 }
 
 bool SurfaceInterceptorTest::transparentRegionHintUpdateFound(const SurfaceChange& change,
-        bool foundTransparentRegion)
-{
+        bool foundTransparentRegion) {
     auto traceRegion = change.transparent_region_hint().region(0);
     bool hasLeft(traceRegion.left() == CROP_UPDATE.left);
     bool hasTop(traceRegion.top() == CROP_UPDATE.top);
@@ -489,84 +506,72 @@
     bool hasBottom(traceRegion.bottom() == CROP_UPDATE.bottom);
     if (hasLeft && hasRight && hasTop && hasBottom && !foundTransparentRegion) {
         foundTransparentRegion = true;
-    }
-    else if (hasLeft && hasRight && hasTop && hasBottom && foundTransparentRegion) {
+    } else if (hasLeft && hasRight && hasTop && hasBottom && foundTransparentRegion) {
         [] () { FAIL(); }();
     }
     return foundTransparentRegion;
 }
 
 bool SurfaceInterceptorTest::layerStackUpdateFound(const SurfaceChange& change,
-        bool foundLayerStack)
-{
+        bool foundLayerStack) {
     bool hasLayerStackUpdate(change.layer_stack().layer_stack() == STACK_UPDATE);
     if (hasLayerStackUpdate && !foundLayerStack) {
         foundLayerStack = true;
-    }
-    else if (hasLayerStackUpdate && foundLayerStack) {
+    } else if (hasLayerStackUpdate && foundLayerStack) {
         [] () { FAIL(); }();
     }
     return foundLayerStack;
 }
 
 bool SurfaceInterceptorTest::hiddenFlagUpdateFound(const SurfaceChange& change,
-        bool foundHiddenFlag)
-{
+        bool foundHiddenFlag) {
     bool hasHiddenFlag(change.hidden_flag().hidden_flag());
     if (hasHiddenFlag && !foundHiddenFlag) {
         foundHiddenFlag = true;
-    }
-    else if (hasHiddenFlag && foundHiddenFlag) {
+    } else if (hasHiddenFlag && foundHiddenFlag) {
         [] () { FAIL(); }();
     }
     return foundHiddenFlag;
 }
 
 bool SurfaceInterceptorTest::opaqueFlagUpdateFound(const SurfaceChange& change,
-        bool foundOpaqueFlag)
-{
+        bool foundOpaqueFlag) {
     bool hasOpaqueFlag(change.opaque_flag().opaque_flag());
     if (hasOpaqueFlag && !foundOpaqueFlag) {
         foundOpaqueFlag = true;
-    }
-    else if (hasOpaqueFlag && foundOpaqueFlag) {
+    } else if (hasOpaqueFlag && foundOpaqueFlag) {
         [] () { FAIL(); }();
     }
     return foundOpaqueFlag;
 }
 
 bool SurfaceInterceptorTest::secureFlagUpdateFound(const SurfaceChange& change,
-        bool foundSecureFlag)
-{
+        bool foundSecureFlag) {
     bool hasSecureFlag(change.secure_flag().secure_flag());
     if (hasSecureFlag && !foundSecureFlag) {
         foundSecureFlag = true;
-    }
-    else if (hasSecureFlag && foundSecureFlag) {
+    } else if (hasSecureFlag && foundSecureFlag) {
         [] () { FAIL(); }();
     }
     return foundSecureFlag;
 }
 
 bool SurfaceInterceptorTest::deferredTransactionUpdateFound(const SurfaceChange& change,
-        bool foundDeferred)
-{
+        bool foundDeferred) {
     bool hasId(change.deferred_transaction().layer_id() == mBGLayerId);
     bool hasFrameNumber(change.deferred_transaction().frame_number() == DEFERRED_UPDATE);
     if (hasId && hasFrameNumber && !foundDeferred) {
         foundDeferred = true;
-    }
-    else if (hasId && hasFrameNumber && foundDeferred) {
+    } else if (hasId && hasFrameNumber && foundDeferred) {
         [] () { FAIL(); }();
     }
     return foundDeferred;
 }
 
-bool SurfaceInterceptorTest::surfaceUpdateFound(Trace* trace,
-        SurfaceChange::SurfaceChangeCase changeCase)
-{
+bool SurfaceInterceptorTest::surfaceUpdateFound(const Trace& trace,
+        SurfaceChange::SurfaceChangeCase changeCase) {
     bool foundUpdate = false;
-    for (const auto& increment : *trace->mutable_increment()) {
+    for (const auto& increment : trace.increment()) {
         if (increment.increment_case() == increment.kTransaction) {
             for (const auto& change : increment.transaction().surface_change()) {
                 if (change.id() == mBGLayerId && change.SurfaceChange_case() == changeCase) {
@@ -624,7 +629,7 @@
     return foundUpdate;
 }
 
-void SurfaceInterceptorTest::assertAllUpdatesFound(Trace* trace) {
+void SurfaceInterceptorTest::assertAllUpdatesFound(const Trace& trace) {
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kPosition));
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kSize));
     ASSERT_TRUE(surfaceUpdateFound(trace, SurfaceChange::SurfaceChangeCase::kAlpha));
@@ -642,24 +647,23 @@
 }
 
 bool SurfaceInterceptorTest::surfaceCreationFound(const Increment& increment, bool foundSurface) {
-    bool isMatch(increment.surface_creation().name() == LAYER_NAME &&
+    bool isMatch(increment.surface_creation().name() == UNIQUE_LAYER_NAME &&
             increment.surface_creation().w() == SIZE_UPDATE &&
             increment.surface_creation().h() == SIZE_UPDATE);
     if (isMatch && !foundSurface) {
         foundSurface = true;
-    }
-    else if (isMatch && foundSurface) {
+    } else if (isMatch && foundSurface) {
         [] () { FAIL(); }();
     }
     return foundSurface;
 }
 
-bool SurfaceInterceptorTest::surfaceDeletionFound(const Increment& increment, bool foundSurface) {
-    bool isMatch(increment.surface_deletion().id() == mTargetId);
+bool SurfaceInterceptorTest::surfaceDeletionFound(const Increment& increment,
+        const int32_t targetId, bool foundSurface) {
+    bool isMatch(increment.surface_deletion().id() == targetId);
     if (isMatch && !foundSurface) {
         foundSurface = true;
-    }
-    else if (isMatch && foundSurface) {
+    } else if (isMatch && foundSurface) {
         [] () { FAIL(); }();
     }
     return foundSurface;
@@ -670,42 +674,45 @@
             increment.display_creation().is_secure());
     if (isMatch && !foundDisplay) {
         foundDisplay = true;
-    }
-    else if (isMatch && foundDisplay) {
+    } else if (isMatch && foundDisplay) {
         [] () { FAIL(); }();
     }
     return foundDisplay;
 }
 
-bool SurfaceInterceptorTest::displayDeletionFound(const Increment& increment, bool foundDisplay) {
-    bool isMatch(increment.display_deletion().id() == mTargetId);
+bool SurfaceInterceptorTest::displayDeletionFound(const Increment& increment,
+        const int32_t targetId, bool foundDisplay) {
+    bool isMatch(increment.display_deletion().id() == targetId);
     if (isMatch && !foundDisplay) {
         foundDisplay = true;
-    }
-    else if (isMatch && foundDisplay) {
+    } else if (isMatch && foundDisplay) {
         [] () { FAIL(); }();
     }
     return foundDisplay;
 }
 
-bool SurfaceInterceptorTest::singleIncrementFound(Trace* trace,
-        Increment::IncrementCase incrementCase)
-{
+bool SurfaceInterceptorTest::singleIncrementFound(const Trace& trace,
+        Increment::IncrementCase incrementCase) {
     bool foundIncrement = false;
-    for (const auto& increment : *trace->mutable_increment()) {
+    for (const auto& increment : trace.increment()) {
         if (increment.increment_case() == incrementCase) {
+            int32_t targetId = 0;
             switch (incrementCase) {
                 case Increment::IncrementCase::kSurfaceCreation:
                     foundIncrement = surfaceCreationFound(increment, foundIncrement);
                     break;
                 case Increment::IncrementCase::kSurfaceDeletion:
-                    foundIncrement = surfaceDeletionFound(increment, foundIncrement);
+                    // Find the id of created surface.
+                    targetId = getSurfaceId(trace, UNIQUE_LAYER_NAME);
+                    foundIncrement = surfaceDeletionFound(increment, targetId, foundIncrement);
                     break;
                 case Increment::IncrementCase::kDisplayCreation:
                     foundIncrement = displayCreationFound(increment, foundIncrement);
                     break;
                 case Increment::IncrementCase::kDisplayDeletion:
-                    foundIncrement = displayDeletionFound(increment, foundIncrement);
+                    // Find the id of created display.
+                    targetId = getDisplayId(trace, DISPLAY_NAME.string());
+                    foundIncrement = displayDeletionFound(increment, targetId, foundIncrement);
                     break;
                 default:
                     /* code */
@@ -716,9 +723,9 @@
     return foundIncrement;
 }
 
-bool SurfaceInterceptorTest::bufferUpdatesFound(Trace* trace) {
+bool SurfaceInterceptorTest::bufferUpdatesFound(const Trace& trace) {
     uint32_t updates = 0;
-    for (const auto& inc : *trace->mutable_increment()) {
+    for (const auto& inc : trace.increment()) {
         if (inc.increment_case() == inc.kBufferUpdate && inc.buffer_update().id() == mBGLayerId) {
             updates++;
         }
@@ -792,14 +799,8 @@
 }
 
 TEST_F(SurfaceInterceptorTest, InterceptAllUpdatesWorks) {
-    enableInterceptor();
-    runAllUpdates();
-    disableInterceptor();
-
-    // Find all of the updates in the single trace
-    Trace capturedTrace;
-    ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
-    assertAllUpdatesFound(&capturedTrace);
+    captureTest(&SurfaceInterceptorTest::runAllUpdates,
+                &SurfaceInterceptorTest::assertAllUpdatesFound);
 }
 
 TEST_F(SurfaceInterceptorTest, InterceptSurfaceCreationWorks) {
@@ -808,16 +809,15 @@
 }
 
 TEST_F(SurfaceInterceptorTest, InterceptSurfaceDeletionWorks) {
+    enableInterceptor();
     sp<SurfaceControl> layerToDelete = mComposerClient->createSurface(String8(LAYER_NAME),
             SIZE_UPDATE, SIZE_UPDATE, PIXEL_FORMAT_RGBA_8888, 0);
-    this->mTargetId = getSurfaceId(LAYER_NAME);
-    enableInterceptor();
     mComposerClient->destroySurface(layerToDelete->getHandle());
     disableInterceptor();
 
     Trace capturedTrace;
     ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
-    ASSERT_TRUE(singleIncrementFound(&capturedTrace, Increment::IncrementCase::kSurfaceDeletion));
+    ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceDeletion));
 }
 
 TEST_F(SurfaceInterceptorTest, InterceptDisplayCreationWorks) {
@@ -826,21 +826,24 @@
 }
 
 TEST_F(SurfaceInterceptorTest, InterceptDisplayDeletionWorks) {
-    captureTest(&SurfaceInterceptorTest::displayDeletion,
-            Increment::IncrementCase::kDisplayDeletion);
+    enableInterceptor();
+    runInTransaction(&SurfaceInterceptorTest::displayDeletion);
+    disableInterceptor();
+    Trace capturedTrace;
+    ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
+    ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kDisplayDeletion));
 }
 
 TEST_F(SurfaceInterceptorTest, InterceptBufferUpdateWorks) {
-    nBufferUpdates();
-    Trace capturedTrace;
-    ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
-    ASSERT_TRUE(bufferUpdatesFound(&capturedTrace));
+    captureTest(&SurfaceInterceptorTest::nBufferUpdates,
+            &SurfaceInterceptorTest::bufferUpdatesFound);
 }
 
 // If the interceptor is enabled while buffer updates are being pushed, the interceptor should
 // first create a snapshot of the existing displays and surfaces and then start capturing
 // the buffer updates
 TEST_F(SurfaceInterceptorTest, InterceptWhileBufferUpdatesWorks) {
+    setupBackgroundSurface();
     std::thread bufferUpdates(&SurfaceInterceptorTest::nBufferUpdates, this);
     enableInterceptor();
     disableInterceptor();
@@ -854,6 +857,7 @@
 
 TEST_F(SurfaceInterceptorTest, InterceptSimultaneousUpdatesWorks) {
     enableInterceptor();
+    setupBackgroundSurface();
     std::thread bufferUpdates(&SurfaceInterceptorTest::nBufferUpdates, this);
     std::thread surfaceUpdates(&SurfaceInterceptorTest::runAllUpdates, this);
     runInTransaction(&SurfaceInterceptorTest::surfaceCreation);
@@ -863,10 +867,11 @@
 
     Trace capturedTrace;
     ASSERT_EQ(NO_ERROR, readProtoFile(&capturedTrace));
+    preProcessTrace(capturedTrace);
 
-    assertAllUpdatesFound(&capturedTrace);
-    ASSERT_TRUE(bufferUpdatesFound(&capturedTrace));
-    ASSERT_TRUE(singleIncrementFound(&capturedTrace, Increment::IncrementCase::kSurfaceCreation));
+    assertAllUpdatesFound(capturedTrace);
+    ASSERT_TRUE(bufferUpdatesFound(capturedTrace));
+    ASSERT_TRUE(singleIncrementFound(capturedTrace, Increment::IncrementCase::kSurfaceCreation));
 }
 
 }
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 9b31985..070bd51 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -1095,7 +1095,7 @@
     EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
 }
 
-TEST_F(ChildLayerTest, DetachChildren) {
+TEST_F(ChildLayerTest, DetachChildrenSameClient) {
     {
         TransactionScope ts(*sFakeComposer);
         ts.show(mChild);
@@ -1111,14 +1111,59 @@
 
     {
         TransactionScope ts(*sFakeComposer);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
         ts.detachChildren(mFGSurfaceControl);
     }
 
     {
         TransactionScope ts(*sFakeComposer);
+        ts.setPosition(mFGSurfaceControl, 64, 64);
         ts.hide(mChild);
     }
 
+    std::vector<RenderState> refFrame(2);
+    refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+    refFrame[FG_LAYER] = mBaseFrame[FG_LAYER];
+
+    EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildLayerTest, DetachChildrenDifferentClient) {
+    sp<SurfaceComposerClient> newComposerClient = new SurfaceComposerClient;
+    sp<SurfaceControl> childNewClient =
+            newComposerClient->createSurface(String8("New Child Test Surface"), 10, 10,
+                                             PIXEL_FORMAT_RGBA_8888, 0, mFGSurfaceControl.get());
+    ASSERT_TRUE(childNewClient != nullptr);
+    ASSERT_TRUE(childNewClient->isValid());
+    fillSurfaceRGBA8(childNewClient, LIGHT_GRAY);
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.hide(mChild);
+        ts.show(childNewClient);
+        ts.setPosition(childNewClient, 10, 10);
+        ts.setPosition(mFGSurfaceControl, 64, 64);
+    }
+
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{64, 64, 64 + 64, 64 + 64};
+    referenceFrame[CHILD_LAYER].mDisplayFrame =
+            hwc_rect_t{64 + 10, 64 + 10, 64 + 10 + 10, 64 + 10 + 10};
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.detachChildren(mFGSurfaceControl);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
+    }
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setPosition(mFGSurfaceControl, 64, 64);
+        ts.setPosition(childNewClient, 0, 0);
+        ts.hide(childNewClient);
+    }
+
     // Nothing should have changed. The child control becomes a no-op
     // zombie on detach. See comments for detachChildren in the
     // SurfaceControl.h file.
@@ -1217,6 +1262,81 @@
     sFakeComposer->runVSyncAndWait();
 }
 
+class ChildColorLayerTest : public ChildLayerTest {
+protected:
+    void SetUp() override {
+        TransactionTest::SetUp();
+        mChild = mComposerClient->createSurface(String8("Child surface"), 10, 10,
+                                                PIXEL_FORMAT_RGBA_8888,
+                                                ISurfaceComposerClient::eFXSurfaceColor,
+                                                mFGSurfaceControl.get());
+        {
+            TransactionScope ts(*sFakeComposer);
+            ts.setColor(mChild,
+                        {LIGHT_GRAY.r / 255.0f, LIGHT_GRAY.g / 255.0f, LIGHT_GRAY.b / 255.0f});
+        }
+
+        sFakeComposer->runVSyncAndWait();
+        mBaseFrame.push_back(makeSimpleRect(64, 64, 64 + 10, 64 + 10));
+        mBaseFrame[CHILD_LAYER].mSourceCrop = hwc_frect_t{0.0f, 0.0f, 0.0f, 0.0f};
+        mBaseFrame[CHILD_LAYER].mSwapCount = 0;
+        ASSERT_EQ(2, sFakeComposer->getFrameCount());
+        ASSERT_TRUE(framesAreSame(mBaseFrame, sFakeComposer->getLatestFrame()));
+    }
+};
+
+TEST_F(ChildColorLayerTest, LayerAlpha) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 0, 0);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
+        ts.setAlpha(mChild, 0.5);
+    }
+
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+    referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setAlpha(mFGSurfaceControl, 0.5);
+    }
+
+    auto referenceFrame2 = referenceFrame;
+    referenceFrame2[FG_LAYER].mPlaneAlpha = 0.5f;
+    referenceFrame2[CHILD_LAYER].mPlaneAlpha = 0.25f;
+    EXPECT_TRUE(framesAreSame(referenceFrame2, sFakeComposer->getLatestFrame()));
+}
+
+TEST_F(ChildColorLayerTest, LayerZeroAlpha) {
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.show(mChild);
+        ts.setPosition(mChild, 0, 0);
+        ts.setPosition(mFGSurfaceControl, 0, 0);
+        ts.setAlpha(mChild, 0.5);
+    }
+
+    auto referenceFrame = mBaseFrame;
+    referenceFrame[FG_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 64, 64};
+    referenceFrame[CHILD_LAYER].mDisplayFrame = hwc_rect_t{0, 0, 10, 10};
+    referenceFrame[CHILD_LAYER].mPlaneAlpha = 0.5f;
+    EXPECT_TRUE(framesAreSame(referenceFrame, sFakeComposer->getLatestFrame()));
+
+    {
+        TransactionScope ts(*sFakeComposer);
+        ts.setAlpha(mFGSurfaceControl, 0.0f);
+    }
+
+    std::vector<RenderState> refFrame(1);
+    refFrame[BG_LAYER] = mBaseFrame[BG_LAYER];
+
+    EXPECT_TRUE(framesAreSame(refFrame, sFakeComposer->getLatestFrame()));
+}
+
 class LatchingTest : public TransactionTest {
 protected:
     void lockAndFillFGBuffer() { fillSurfaceRGBA8(mFGSurfaceControl, RED, false); }
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 9949bfa..95c54b8 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -18,6 +18,7 @@
     test_suites: ["device-tests"],
     srcs: [
         ":libsurfaceflinger_sources",
+        "DisplayIdentificationTest.cpp",
         "DisplayTransactionTest.cpp",
         "EventControlThreadTest.cpp",
         "EventThreadTest.cpp",
diff --git a/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
new file mode 100644
index 0000000..9113171
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/DisplayIdentificationTest.cpp
@@ -0,0 +1,144 @@
+/*
+ * Copyright (C) 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include "DisplayHardware/DisplayIdentification.h"
+
+namespace android {
+namespace {
+
+const unsigned char kInternalEdid[] =
+        "\x00\xff\xff\xff\xff\xff\xff\x00\x4c\xa3\x42\x31\x00\x00\x00\x00"
+        "\x00\x15\x01\x03\x80\x1a\x10\x78\x0a\xd3\xe5\x95\x5c\x60\x90\x27"
+        "\x19\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
+        "\x01\x01\x01\x01\x01\x01\x9e\x1b\x00\xa0\x50\x20\x12\x30\x10\x30"
+        "\x13\x00\x05\xa3\x10\x00\x00\x19\x00\x00\x00\x0f\x00\x00\x00\x00"
+        "\x00\x00\x00\x00\x00\x23\x87\x02\x64\x00\x00\x00\x00\xfe\x00\x53"
+        "\x41\x4d\x53\x55\x4e\x47\x0a\x20\x20\x20\x20\x20\x00\x00\x00\xfe"
+        "\x00\x31\x32\x31\x41\x54\x31\x31\x2d\x38\x30\x31\x0a\x20\x00\x45";
+
+const unsigned char kExternalEdid[] =
+        "\x00\xff\xff\xff\xff\xff\xff\x00\x22\xf0\x6c\x28\x01\x01\x01\x01"
+        "\x02\x16\x01\x04\xb5\x40\x28\x78\xe2\x8d\x85\xad\x4f\x35\xb1\x25"
+        "\x0e\x50\x54\x00\x00\x00\x01\x01\x01\x01\x01\x01\x01\x01\x01\x01"
+        "\x01\x01\x01\x01\x01\x01\xe2\x68\x00\xa0\xa0\x40\x2e\x60\x30\x20"
+        "\x36\x00\x81\x90\x21\x00\x00\x1a\xbc\x1b\x00\xa0\x50\x20\x17\x30"
+        "\x30\x20\x36\x00\x81\x90\x21\x00\x00\x1a\x00\x00\x00\xfc\x00\x48"
+        "\x50\x20\x5a\x52\x33\x30\x77\x0a\x20\x20\x20\x20\x00\x00\x00\xff"
+        "\x00\x43\x4e\x34\x32\x30\x32\x31\x33\x37\x51\x0a\x20\x20\x00\x71";
+
+// Extended EDID with timing extension.
+const unsigned char kExternalEedid[] =
+        "\x00\xff\xff\xff\xff\xff\xff\x00\x4c\x2d\xfe\x08\x00\x00\x00\x00"
+        "\x29\x15\x01\x03\x80\x10\x09\x78\x0a\xee\x91\xa3\x54\x4c\x99\x26"
+        "\x0f\x50\x54\xbd\xef\x80\x71\x4f\x81\xc0\x81\x00\x81\x80\x95\x00"
+        "\xa9\xc0\xb3\x00\x01\x01\x02\x3a\x80\x18\x71\x38\x2d\x40\x58\x2c"
+        "\x45\x00\xa0\x5a\x00\x00\x00\x1e\x66\x21\x56\xaa\x51\x00\x1e\x30"
+        "\x46\x8f\x33\x00\xa0\x5a\x00\x00\x00\x1e\x00\x00\x00\xfd\x00\x18"
+        "\x4b\x0f\x51\x17\x00\x0a\x20\x20\x20\x20\x20\x20\x00\x00\x00\xfc"
+        "\x00\x53\x41\x4d\x53\x55\x4e\x47\x0a\x20\x20\x20\x20\x20\x01\x1d"
+        "\x02\x03\x1f\xf1\x47\x90\x04\x05\x03\x20\x22\x07\x23\x09\x07\x07"
+        "\x83\x01\x00\x00\xe2\x00\x0f\x67\x03\x0c\x00\x20\x00\xb8\x2d\x01"
+        "\x1d\x80\x18\x71\x1c\x16\x20\x58\x2c\x25\x00\xa0\x5a\x00\x00\x00"
+        "\x9e\x01\x1d\x00\x72\x51\xd0\x1e\x20\x6e\x28\x55\x00\xa0\x5a\x00"
+        "\x00\x00\x1e\x8c\x0a\xd0\x8a\x20\xe0\x2d\x10\x10\x3e\x96\x00\xa0"
+        "\x5a\x00\x00\x00\x18\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+        "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xc6";
+
+template <size_t N>
+DisplayIdentificationData asDisplayIdentificationData(const unsigned char (&bytes)[N]) {
+    return DisplayIdentificationData(bytes, bytes + N - 1);
+}
+
+} // namespace
+
+TEST(DisplayIdentificationTest, isEdid) {
+    EXPECT_FALSE(isEdid({}));
+
+    EXPECT_TRUE(isEdid(asDisplayIdentificationData(kInternalEdid)));
+    EXPECT_TRUE(isEdid(asDisplayIdentificationData(kExternalEdid)));
+    EXPECT_TRUE(isEdid(asDisplayIdentificationData(kExternalEedid)));
+}
+
+TEST(DisplayIdentificationTest, parseEdid) {
+    auto edid = parseEdid(asDisplayIdentificationData(kInternalEdid));
+    ASSERT_TRUE(edid);
+    EXPECT_EQ(0x4ca3u, edid->manufacturerId);
+    EXPECT_STREQ("SEC", edid->pnpId.data());
+    // ASCII text should be used as fallback if display name and serial number are missing.
+    EXPECT_EQ("121AT11-801", edid->displayName);
+
+    edid = parseEdid(asDisplayIdentificationData(kExternalEdid));
+    ASSERT_TRUE(edid);
+    EXPECT_EQ(0x22f0u, edid->manufacturerId);
+    EXPECT_STREQ("HWP", edid->pnpId.data());
+    EXPECT_EQ("HP ZR30w", edid->displayName);
+
+    edid = parseEdid(asDisplayIdentificationData(kExternalEedid));
+    ASSERT_TRUE(edid);
+    EXPECT_EQ(0x4c2du, edid->manufacturerId);
+    EXPECT_STREQ("SAM", edid->pnpId.data());
+    EXPECT_EQ("SAMSUNG", edid->displayName);
+}
+
+TEST(DisplayIdentificationTest, parseInvalidEdid) {
+    EXPECT_FALSE(isEdid({}));
+    EXPECT_FALSE(parseEdid({}));
+
+    // Display name must be printable.
+    auto data = asDisplayIdentificationData(kExternalEdid);
+    data[97] = '\x1b';
+    auto edid = parseEdid(data);
+    ASSERT_TRUE(edid);
+    // Serial number should be used as fallback if display name is invalid.
+    EXPECT_EQ("CN4202137Q", edid->displayName);
+
+    // Parsing should succeed even if EDID is truncated.
+    data.pop_back();
+    edid = parseEdid(data);
+    ASSERT_TRUE(edid);
+    EXPECT_EQ("CN4202137Q", edid->displayName);
+}
+
+TEST(DisplayIdentificationTest, getPnpId) {
+    EXPECT_FALSE(getPnpId(0));
+    EXPECT_FALSE(getPnpId(static_cast<uint16_t>(-1)));
+
+    EXPECT_STREQ("SEC", getPnpId(0x4ca3u).value_or(PnpId{}).data());
+    EXPECT_STREQ("HWP", getPnpId(0x22f0u).value_or(PnpId{}).data());
+    EXPECT_STREQ("SAM", getPnpId(0x4c2du).value_or(PnpId{}).data());
+}
+
+TEST(DisplayIdentificationTest, generateDisplayId) {
+    const auto primaryId = generateDisplayId(0, asDisplayIdentificationData(kInternalEdid));
+    ASSERT_TRUE(primaryId);
+
+    const auto secondaryId = generateDisplayId(1, asDisplayIdentificationData(kExternalEdid));
+    ASSERT_TRUE(secondaryId);
+
+    const auto tertiaryId = generateDisplayId(2, asDisplayIdentificationData(kExternalEedid));
+    ASSERT_TRUE(tertiaryId);
+
+    // Display IDs should be unique.
+    EXPECT_NE(primaryId, secondaryId);
+    EXPECT_NE(primaryId, tertiaryId);
+    EXPECT_NE(secondaryId, tertiaryId);
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
index 9b308bf..58d3879 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTest.cpp
@@ -207,11 +207,11 @@
 }
 
 bool DisplayTransactionTest::hasDisplayDevice(sp<IBinder> displayToken) {
-    return mFlinger.mutableDisplays().indexOfKey(displayToken) >= 0;
+    return mFlinger.mutableDisplays().count(displayToken) == 1;
 }
 
 sp<DisplayDevice> DisplayTransactionTest::getDisplayDevice(sp<IBinder> displayToken) {
-    return mFlinger.mutableDisplays().valueFor(displayToken);
+    return mFlinger.mutableDisplays()[displayToken];
 }
 
 bool DisplayTransactionTest::hasCurrentDisplayState(sp<IBinder> displayToken) {
@@ -234,8 +234,8 @@
  *
  */
 
-template <DisplayDevice::DisplayType type, DisplayDevice::DisplayType hwcId, int width, int height,
-          Critical critical, Async async, Secure secure, int grallocUsage>
+template <DisplayDevice::DisplayType type, DisplayDevice::DisplayType displayId, int width,
+          int height, Critical critical, Async async, Secure secure, int grallocUsage>
 struct DisplayVariant {
     // The display width and height
     static constexpr int WIDTH = width;
@@ -245,7 +245,9 @@
 
     // The type for this display
     static constexpr DisplayDevice::DisplayType TYPE = type;
-    static constexpr DisplayDevice::DisplayType HWCOMPOSER_ID = hwcId;
+    static_assert(TYPE != DisplayDevice::DISPLAY_ID_INVALID);
+
+    static constexpr DisplayDevice::DisplayType DISPLAY_ID = displayId;
 
     // When creating native window surfaces for the framebuffer, whether those should be critical
     static constexpr Critical CRITICAL = critical;
@@ -257,7 +259,7 @@
     static constexpr Secure SECURE = secure;
 
     static auto makeFakeExistingDisplayInjector(DisplayTransactionTest* test) {
-        auto injector = FakeDisplayDeviceInjector(test->mFlinger, TYPE, HWCOMPOSER_ID);
+        auto injector = FakeDisplayDeviceInjector(test->mFlinger, TYPE, DISPLAY_ID);
         injector.setSecure(static_cast<bool>(SECURE));
         return injector;
     }
@@ -353,6 +355,8 @@
                     getDisplayAttribute(HWC_DISPLAY_ID, HWC_ACTIVE_CONFIG_ID,
                                         IComposerClient::Attribute::DPI_Y, _))
                 .WillOnce(DoAll(SetArgPointee<3>(DEFAULT_DPI), Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer, getDisplayIdentificationData(HWC_DISPLAY_ID, _, _))
+                .WillRepeatedly(Return(Error::UNSUPPORTED));
     }
 
     // Called by tests to set up HWC call expectations
@@ -383,11 +387,6 @@
                                  DisplayVariant<type, type, width, height, critical, Async::FALSE,
                                                 Secure::TRUE, GRALLOC_USAGE_PHYSICAL_DISPLAY>> {};
 
-// An invalid display
-using InvalidDisplayVariant =
-        DisplayVariant<DisplayDevice::DISPLAY_ID_INVALID, DisplayDevice::DISPLAY_ID_INVALID, 0, 0,
-                       Critical::FALSE, Async::FALSE, Secure::FALSE, 0>;
-
 // A primary display is a physical display that is critical
 using PrimaryDisplayVariant =
         PhysicalDisplayVariant<1001, DisplayDevice::DISPLAY_PRIMARY, 3840, 2160, Critical::TRUE>;
@@ -578,7 +577,7 @@
 struct NonHwcPerFrameMetadataSupportVariant {
     static constexpr int PER_FRAME_METADATA_KEYS = 0;
     static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(_, _)).Times(0);
+        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(_)).Times(0);
     }
 };
 
@@ -586,9 +585,8 @@
 struct NoPerFrameMetadataSupportVariant {
     static constexpr int PER_FRAME_METADATA_KEYS = 0;
     static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<PerFrameMetadataKey>()),
-                                Return(Error::NONE)));
+        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
+                .WillOnce(Return(std::vector<PerFrameMetadataKey>()));
     }
 };
 
@@ -596,8 +594,8 @@
 struct Smpte2086PerFrameMetadataSupportVariant {
     static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::SMPTE2086;
     static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<PerFrameMetadataKey>({
+        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
+                .WillOnce(Return(std::vector<PerFrameMetadataKey>({
                                         PerFrameMetadataKey::DISPLAY_RED_PRIMARY_X,
                                         PerFrameMetadataKey::DISPLAY_RED_PRIMARY_Y,
                                         PerFrameMetadataKey::DISPLAY_GREEN_PRIMARY_X,
@@ -608,8 +606,7 @@
                                         PerFrameMetadataKey::WHITE_POINT_Y,
                                         PerFrameMetadataKey::MAX_LUMINANCE,
                                         PerFrameMetadataKey::MIN_LUMINANCE,
-                                })),
-                                Return(Error::NONE)));
+                                })));
     }
 };
 
@@ -617,12 +614,11 @@
 struct Cta861_3_PerFrameMetadataSupportVariant {
     static constexpr int PER_FRAME_METADATA_KEYS = HdrMetadata::Type::CTA861_3;
     static void setupComposerCallExpectations(DisplayTransactionTest* test) {
-        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID, _))
-                .WillOnce(DoAll(SetArgPointee<1>(std::vector<PerFrameMetadataKey>({
+        EXPECT_CALL(*test->mComposer, getPerFrameMetadataKeys(Display::HWC_DISPLAY_ID))
+                .WillOnce(Return(std::vector<PerFrameMetadataKey>({
                                         PerFrameMetadataKey::MAX_CONTENT_LIGHT_LEVEL,
                                         PerFrameMetadataKey::MAX_FRAME_AVERAGE_LIGHT_LEVEL,
-                                })),
-                                Return(Error::NONE)));
+                                })));
     }
 };
 
@@ -658,8 +654,7 @@
 using SimpleHwcVirtualDisplayVariant = HwcVirtualDisplayVariant<1024, 768, Secure::TRUE>;
 using HwcVirtualDisplayCase =
         Case<SimpleHwcVirtualDisplayVariant, WideColorSupportNotConfiguredVariant,
-             HdrNotSupportedVariant<SimpleHwcVirtualDisplayVariant>,
-             NoPerFrameMetadataSupportVariant<SimpleHwcVirtualDisplayVariant>>;
+             NonHwcDisplayHdrSupportVariant, NonHwcPerFrameMetadataSupportVariant>;
 using WideColorP3ColorimetricDisplayCase =
         Case<PrimaryDisplayVariant, WideColorP3ColorimetricSupportedVariant<PrimaryDisplayVariant>,
              HdrNotSupportedVariant<PrimaryDisplayVariant>,
@@ -684,9 +679,7 @@
         Case<PrimaryDisplayVariant, WideColorNotSupportedVariant<PrimaryDisplayVariant>,
              HdrNotSupportedVariant<PrimaryDisplayVariant>,
              Cta861_3_PerFrameMetadataSupportVariant<PrimaryDisplayVariant>>;
-using InvalidDisplayCase = Case<InvalidDisplayVariant, WideColorSupportNotConfiguredVariant,
-                                NonHwcDisplayHdrSupportVariant,
-                                NoPerFrameMetadataSupportVariant<InvalidDisplayVariant>>;
+
 /* ------------------------------------------------------------------------
  *
  * SurfaceFlinger::onHotplugReceived
@@ -694,8 +687,8 @@
 
 TEST_F(DisplayTransactionTest, hotplugEnqueuesEventsForDisplayTransaction) {
     constexpr int currentSequenceId = 123;
-    constexpr hwc2_display_t displayId1 = 456;
-    constexpr hwc2_display_t displayId2 = 654;
+    constexpr hwc2_display_t hwcDisplayId1 = 456;
+    constexpr hwc2_display_t hwcDisplayId2 = 654;
 
     // --------------------------------------------------------------------
     // Preconditions
@@ -718,8 +711,8 @@
     // Invocation
 
     // Simulate two hotplug events (a connect and a disconnect)
-    mFlinger.onHotplugReceived(currentSequenceId, displayId1, HWC2::Connection::Connected);
-    mFlinger.onHotplugReceived(currentSequenceId, displayId2, HWC2::Connection::Disconnected);
+    mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId1, HWC2::Connection::Connected);
+    mFlinger.onHotplugReceived(currentSequenceId, hwcDisplayId2, HWC2::Connection::Disconnected);
 
     // --------------------------------------------------------------------
     // Postconditions
@@ -730,9 +723,9 @@
     // All events should be in the pending event queue.
     const auto& pendingEvents = mFlinger.mutablePendingHotplugEvents();
     ASSERT_EQ(2u, pendingEvents.size());
-    EXPECT_EQ(displayId1, pendingEvents[0].display);
+    EXPECT_EQ(hwcDisplayId1, pendingEvents[0].hwcDisplayId);
     EXPECT_EQ(HWC2::Connection::Connected, pendingEvents[0].connection);
-    EXPECT_EQ(displayId2, pendingEvents[1].display);
+    EXPECT_EQ(hwcDisplayId2, pendingEvents[1].hwcDisplayId);
     EXPECT_EQ(HWC2::Connection::Disconnected, pendingEvents[1].connection);
 }
 
@@ -1032,7 +1025,10 @@
     // --------------------------------------------------------------------
     // Invocation
 
-    auto state = DisplayDeviceState(Case::Display::TYPE, static_cast<bool>(Case::Display::SECURE));
+    DisplayDeviceState state;
+    state.type = Case::Display::TYPE;
+    state.isSecure = static_cast<bool>(Case::Display::SECURE);
+
     auto device = mFlinger.setupNewDisplayDeviceInternal(displayToken, Case::Display::TYPE, state,
                                                          displaySurface, producer);
 
@@ -1160,13 +1156,23 @@
     Case::PerFrameMetadataSupport::setupComposerCallExpectations(this);
 
     EXPECT_CALL(*mSurfaceInterceptor, saveDisplayCreation(_)).Times(1);
-    EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::TYPE, true)).Times(1);
+    EXPECT_CALL(*mEventThread,
+                onHotplugReceived(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY
+                                          ? EventThread::DisplayType::Primary
+                                          : EventThread::DisplayType::External,
+                                  true))
+            .Times(1);
 }
 
 template <typename Case>
 void HandleTransactionLockedTest::setupCommonCallExpectationsForDisconnectProcessing() {
     EXPECT_CALL(*mSurfaceInterceptor, saveDisplayDeletion(_)).Times(1);
-    EXPECT_CALL(*mEventThread, onHotplugReceived(Case::Display::TYPE, false)).Times(1);
+    EXPECT_CALL(*mEventThread,
+                onHotplugReceived(Case::Display::TYPE == DisplayDevice::DISPLAY_PRIMARY
+                                          ? EventThread::DisplayType::Primary
+                                          : EventThread::DisplayType::External,
+                                  false))
+            .Times(1);
 }
 
 template <typename Case>
@@ -1197,7 +1203,7 @@
     static_assert(0 <= Case::Display::TYPE &&
                           Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
                   "Must use a valid physical display type index for the fixed-size array");
-    auto& displayToken = mFlinger.mutableBuiltinDisplays()[Case::Display::TYPE];
+    auto& displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
     ASSERT_TRUE(displayToken != nullptr);
 
     verifyDisplayIsConnected<Case>(displayToken);
@@ -1303,7 +1309,7 @@
     // The display should not be set up as a built-in display.
     ASSERT_TRUE(0 <= Case::Display::TYPE &&
                 Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES);
-    auto displayToken = mFlinger.mutableBuiltinDisplays()[Case::Display::TYPE];
+    auto displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
     EXPECT_TRUE(displayToken == nullptr);
 
     // The existing token should have been removed
@@ -1396,7 +1402,7 @@
     // The display should not be set up as a primary built-in display.
     ASSERT_TRUE(0 <= Case::Display::TYPE &&
                 Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES);
-    auto displayToken = mFlinger.mutableBuiltinDisplays()[Case::Display::TYPE];
+    auto displayToken = mFlinger.mutableDisplayTokens()[Case::Display::TYPE];
     EXPECT_TRUE(displayToken == nullptr);
 }
 
@@ -1439,7 +1445,7 @@
     static_assert(0 <= Case::Display::TYPE &&
                           Case::Display::TYPE < DisplayDevice::NUM_BUILTIN_DISPLAY_TYPES,
                   "Display type must be a built-in display");
-    EXPECT_NE(existing.token(), mFlinger.mutableBuiltinDisplays()[Case::Display::TYPE]);
+    EXPECT_NE(existing.token(), mFlinger.mutableDisplayTokens()[Case::Display::TYPE]);
 
     // A new display should be connected in its place
 
@@ -1468,7 +1474,11 @@
     // A virtual display was added to the current state, and it has a
     // surface(producer)
     sp<BBinder> displayToken = new BBinder();
-    DisplayDeviceState info(Case::Display::TYPE, static_cast<bool>(Case::Display::SECURE));
+
+    DisplayDeviceState info;
+    info.type = Case::Display::TYPE;
+    info.isSecure = static_cast<bool>(Case::Display::SECURE);
+
     sp<mock::GraphicBufferProducer> surface{new mock::GraphicBufferProducer()};
     info.surface = surface;
     mFlinger.mutableCurrentState().displays.add(displayToken, info);
@@ -1532,7 +1542,11 @@
     // A virtual display was added to the current state, but it does not have a
     // surface.
     sp<BBinder> displayToken = new BBinder();
-    DisplayDeviceState info(Case::Display::TYPE, static_cast<bool>(Case::Display::SECURE));
+
+    DisplayDeviceState info;
+    info.type = Case::Display::TYPE;
+    info.isSecure = static_cast<bool>(Case::Display::SECURE);
+
     mFlinger.mutableCurrentState().displays.add(displayToken, info);
 
     // --------------------------------------------------------------------
@@ -1811,40 +1825,6 @@
     EXPECT_FALSE(hasCurrentDisplayState(displayToken));
 }
 
-TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWithInvalidDisplay) {
-    using Case = InvalidDisplayCase;
-
-    // --------------------------------------------------------------------
-    // Preconditions
-
-    // An invalid display is set up
-    auto display = Case::Display::makeFakeExistingDisplayInjector(this);
-    display.inject();
-
-    // The invalid display has some state
-    display.mutableCurrentDisplayState().layerStack = 654u;
-
-    // The requested display state tries to change the display state.
-    DisplayState state;
-    state.what = DisplayState::eLayerStackChanged;
-    state.token = display.token();
-    state.layerStack = 456;
-
-    // --------------------------------------------------------------------
-    // Invocation
-
-    uint32_t flags = mFlinger.setDisplayStateLocked(state);
-
-    // --------------------------------------------------------------------
-    // Postconditions
-
-    // The returned flags are empty
-    EXPECT_EQ(0u, flags);
-
-    // The current display layer stack value is unchanged.
-    EXPECT_EQ(654u, getCurrentDisplayState(display.token()).layerStack);
-}
-
 TEST_F(DisplayTransactionTest, setDisplayStateLockedDoesNothingWhenNoChanges) {
     using Case = SimplePrimaryDisplayCase;
 
@@ -2671,7 +2651,7 @@
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.inject();
 
-    // The diplay is already set to HWC_POWER_MODE_NORMAL
+    // The display is already set to HWC_POWER_MODE_NORMAL
     display.mutableDisplayDevice()->setPowerMode(HWC_POWER_MODE_NORMAL);
 
     // --------------------------------------------------------------------
@@ -2685,7 +2665,7 @@
     EXPECT_EQ(HWC_POWER_MODE_NORMAL, display.mutableDisplayDevice()->getPowerMode());
 }
 
-TEST_F(SetPowerModeInternalTest, setPowerModeInternalJustSetsInternalStateIfVirtualDisplay) {
+TEST_F(SetPowerModeInternalTest, setPowerModeInternalDoesNothingIfVirtualDisplay) {
     using Case = HwcVirtualDisplayCase;
 
     // --------------------------------------------------------------------
@@ -2700,13 +2680,13 @@
     auto display = Case::Display::makeFakeExistingDisplayInjector(this);
     display.inject();
 
-    // The display is set to HWC_POWER_MODE_OFF
-    getDisplayDevice(display.token())->setPowerMode(HWC_POWER_MODE_OFF);
+    // The display is set to HWC_POWER_MODE_NORMAL
+    getDisplayDevice(display.token())->setPowerMode(HWC_POWER_MODE_NORMAL);
 
     // --------------------------------------------------------------------
     // Invocation
 
-    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), HWC_POWER_MODE_NORMAL);
+    mFlinger.setPowerModeInternal(display.mutableDisplayDevice(), HWC_POWER_MODE_OFF);
 
     // --------------------------------------------------------------------
     // Postconditions
diff --git a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
index 80fdb80..19747bd 100644
--- a/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
+++ b/services/surfaceflinger/tests/unittests/EventThreadTest.cpp
@@ -71,7 +71,8 @@
                                               ConnectionEventRecorder& connectionEventRecorder,
                                               nsecs_t expectedTimestamp, unsigned expectedCount);
     void expectVsyncEventReceivedByConnection(nsecs_t expectedTimestamp, unsigned expectedCount);
-    void expectHotplugEventReceivedByConnection(int expectedDisplayType, bool expectedConnected);
+    void expectHotplugEventReceivedByConnection(EventThread::DisplayType expectedDisplayType,
+                                                bool expectedConnected);
 
     AsyncCallRecorder<void (*)(bool)> mVSyncSetEnabledCallRecorder;
     AsyncCallRecorder<void (*)(VSyncSource::Callback*)> mVSyncSetCallbackCallRecorder;
@@ -169,13 +170,16 @@
                                          expectedCount);
 }
 
-void EventThreadTest::expectHotplugEventReceivedByConnection(int expectedDisplayType,
-                                                             bool expectedConnected) {
+void EventThreadTest::expectHotplugEventReceivedByConnection(
+        EventThread::DisplayType expectedDisplayType, bool expectedConnected) {
+    const uint32_t expectedDisplayId =
+            expectedDisplayType == EventThread::DisplayType::Primary ? 0 : 1;
+
     auto args = mConnectionEventCallRecorder.waitForCall();
     ASSERT_TRUE(args.has_value());
     const auto& event = std::get<0>(args.value());
     EXPECT_EQ(DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG, event.header.type);
-    EXPECT_EQ(static_cast<unsigned>(expectedDisplayType), event.header.id);
+    EXPECT_EQ(expectedDisplayId, event.header.id);
     EXPECT_EQ(expectedConnected, event.hotplug.connected);
 }
 
@@ -394,28 +398,23 @@
 }
 
 TEST_F(EventThreadTest, postHotplugPrimaryDisconnect) {
-    mThread->onHotplugReceived(DisplayDevice::DISPLAY_PRIMARY, false);
-    expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_PRIMARY, false);
+    mThread->onHotplugReceived(EventThread::DisplayType::Primary, false);
+    expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, false);
 }
 
 TEST_F(EventThreadTest, postHotplugPrimaryConnect) {
-    mThread->onHotplugReceived(DisplayDevice::DISPLAY_PRIMARY, true);
-    expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_PRIMARY, true);
+    mThread->onHotplugReceived(EventThread::DisplayType::Primary, true);
+    expectHotplugEventReceivedByConnection(EventThread::DisplayType::Primary, true);
 }
 
 TEST_F(EventThreadTest, postHotplugExternalDisconnect) {
-    mThread->onHotplugReceived(DisplayDevice::DISPLAY_EXTERNAL, false);
-    expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_EXTERNAL, false);
+    mThread->onHotplugReceived(EventThread::DisplayType::External, false);
+    expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, false);
 }
 
 TEST_F(EventThreadTest, postHotplugExternalConnect) {
-    mThread->onHotplugReceived(DisplayDevice::DISPLAY_EXTERNAL, true);
-    expectHotplugEventReceivedByConnection(DisplayDevice::DISPLAY_EXTERNAL, true);
-}
-
-TEST_F(EventThreadTest, postHotplugVirtualDisconnectIsFilteredOut) {
-    mThread->onHotplugReceived(DisplayDevice::DISPLAY_VIRTUAL, false);
-    EXPECT_FALSE(mConnectionEventCallRecorder.waitForUnexpectedCall().has_value());
+    mThread->onHotplugReceived(EventThread::DisplayType::External, true);
+    expectHotplugEventReceivedByConnection(EventThread::DisplayType::External, true);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index acd16fe..5031148 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -64,15 +64,17 @@
         return mFlinger->createDisplay(displayName, secure);
     }
 
-    auto destroyDisplay(const sp<IBinder>& display) { return mFlinger->destroyDisplay(display); }
+    auto destroyDisplay(const sp<IBinder>& displayToken) {
+        return mFlinger->destroyDisplay(displayToken);
+    }
 
     auto resetDisplayState() { return mFlinger->resetDisplayState(); }
 
-    auto setupNewDisplayDeviceInternal(const wp<IBinder>& display, int hwcId,
+    auto setupNewDisplayDeviceInternal(const wp<IBinder>& displayToken, int32_t displayId,
                                        const DisplayDeviceState& state,
                                        const sp<DisplaySurface>& dispSurface,
                                        const sp<IGraphicBufferProducer>& producer) {
-        return mFlinger->setupNewDisplayDeviceInternal(display, hwcId, state, dispSurface,
+        return mFlinger->setupNewDisplayDeviceInternal(displayToken, displayId, state, dispSurface,
                                                        producer);
     }
 
@@ -89,8 +91,9 @@
 
     auto onInitializeDisplays() { return mFlinger->onInitializeDisplays(); }
 
-    auto setPowerModeInternal(const sp<DisplayDevice>& hw, int mode, bool stateLockHeld = false) {
-        return mFlinger->setPowerModeInternal(hw, mode, stateLockHeld);
+    auto setPowerModeInternal(const sp<DisplayDevice>& display, int mode,
+                              bool stateLockHeld = false) {
+        return mFlinger->setPowerModeInternal(display, mode, stateLockHeld);
     }
 
     /* ------------------------------------------------------------------------
@@ -111,7 +114,7 @@
 
     auto& mutableHasWideColorDisplay() { return SurfaceFlinger::hasWideColorDisplay; }
 
-    auto& mutableBuiltinDisplays() { return mFlinger->mBuiltinDisplays; }
+    auto& mutableDisplayTokens() { return mFlinger->mDisplayTokens; }
     auto& mutableCurrentState() { return mFlinger->mCurrentState; }
     auto& mutableDisplays() { return mFlinger->mDisplays; }
     auto& mutableDisplayColorSetting() { return mFlinger->mDisplayColorSetting; }
@@ -217,13 +220,27 @@
             return *this;
         }
 
-        auto& addCapability(HWC2::Capability cap) {
-            mCapabilities.emplace(cap);
+        auto& setCapabilities(const std::unordered_set<HWC2::Capability>* capabilities) {
+            mCapabilities = capabilities;
+            return *this;
+        }
+
+        auto& setPowerAdvisor(Hwc2::PowerAdvisor* powerAdvisor) {
+            mPowerAdvisor = powerAdvisor;
             return *this;
         }
 
         void inject(TestableSurfaceFlinger* flinger, Hwc2::Composer* composer) {
-            auto display = std::make_unique<HWC2Display>(*composer, mPowerAdvisor, mCapabilities,
+            static FakePowerAdvisor defaultPowerAdvisor;
+            if (mPowerAdvisor == nullptr) mPowerAdvisor = &defaultPowerAdvisor;
+            static const std::unordered_set<HWC2::Capability> defaultCapabilities;
+            if (mCapabilities == nullptr) mCapabilities = &defaultCapabilities;
+
+            // Caution - Make sure that any values passed by reference here do
+            // not refer to an instance owned by FakeHwcDisplayInjector. This
+            // class has temporary lifetime, while the constructed HWC2::Display
+            // is much longer lived.
+            auto display = std::make_unique<HWC2Display>(*composer, *mPowerAdvisor, *mCapabilities,
                                                          mHwcDisplayId, mHwcDisplayType);
 
             auto config = HWC2::Display::Config::Builder(*display, mActiveConfig);
@@ -236,7 +253,7 @@
             display->mutableIsConnected() = true;
 
             ASSERT_TRUE(flinger->mutableHwcDisplayData().size() > static_cast<size_t>(mType));
-            flinger->mutableHwcDisplayData()[mType].reset();
+            flinger->mutableHwcDisplayData()[mType] = HWComposer::DisplayData();
             flinger->mutableHwcDisplayData()[mType].hwcDisplay = display.get();
             flinger->mutableHwcDisplaySlots().emplace(mHwcDisplayId, mType);
 
@@ -253,15 +270,15 @@
         int32_t mDpiX = DEFAULT_DPI;
         int32_t mDpiY = DEFAULT_DPI;
         int32_t mActiveConfig = DEFAULT_ACTIVE_CONFIG;
-        std::unordered_set<HWC2::Capability> mCapabilities;
-        FakePowerAdvisor mPowerAdvisor;
+        const std::unordered_set<HWC2::Capability>* mCapabilities = nullptr;
+        Hwc2::PowerAdvisor* mPowerAdvisor = nullptr;
     };
 
     class FakeDisplayDeviceInjector {
     public:
         FakeDisplayDeviceInjector(TestableSurfaceFlinger& flinger, DisplayDevice::DisplayType type,
-                                  int hwcId)
-              : mFlinger(flinger), mType(type), mHwcId(hwcId) {}
+                                  int32_t displayId)
+              : mFlinger(flinger), mType(type), mDisplayId(displayId) {}
 
         sp<IBinder> token() const { return mDisplayToken; }
 
@@ -281,7 +298,7 @@
             return mFlinger.mutableCurrentState().displays.valueFor(mDisplayToken);
         }
 
-        auto& mutableDisplayDevice() { return mFlinger.mutableDisplays().valueFor(mDisplayToken); }
+        auto& mutableDisplayDevice() { return mFlinger.mutableDisplays()[mDisplayToken]; }
 
         auto& setNativeWindow(const sp<ANativeWindow>& nativeWindow) {
             mNativeWindow = nativeWindow;
@@ -306,18 +323,20 @@
         sp<DisplayDevice> inject() {
             std::unordered_map<ui::ColorMode, std::vector<ui::RenderIntent>> hdrAndRenderIntents;
             sp<DisplayDevice> device =
-                    new DisplayDevice(mFlinger.mFlinger.get(), mType, mHwcId, mSecure, mDisplayToken,
-                                      mNativeWindow, mDisplaySurface, std::move(mRenderSurface), 0,
-                                      0, false, HdrCapabilities(), 0, hdrAndRenderIntents,
-                                      HWC_POWER_MODE_NORMAL);
-            mFlinger.mutableDisplays().add(mDisplayToken, device);
+                    new DisplayDevice(mFlinger.mFlinger.get(), mType, mDisplayId, mSecure,
+                                      mDisplayToken, mNativeWindow, mDisplaySurface,
+                                      std::move(mRenderSurface), 0, 0, false, HdrCapabilities(), 0,
+                                      hdrAndRenderIntents, HWC_POWER_MODE_NORMAL);
+            mFlinger.mutableDisplays().emplace(mDisplayToken, device);
 
-            DisplayDeviceState state(mType, mSecure);
+            DisplayDeviceState state;
+            state.type = mType;
+            state.isSecure = mSecure;
             mFlinger.mutableCurrentState().displays.add(mDisplayToken, state);
             mFlinger.mutableDrawingState().displays.add(mDisplayToken, state);
 
             if (mType >= DisplayDevice::DISPLAY_PRIMARY && mType < DisplayDevice::DISPLAY_VIRTUAL) {
-                mFlinger.mutableBuiltinDisplays()[mType] = mDisplayToken;
+                mFlinger.mutableDisplayTokens()[mType] = mDisplayToken;
             }
 
             return device;
@@ -327,7 +346,7 @@
         TestableSurfaceFlinger& mFlinger;
         sp<BBinder> mDisplayToken = new BBinder();
         DisplayDevice::DisplayType mType;
-        int mHwcId;
+        const int32_t mDisplayId;
         sp<ANativeWindow> mNativeWindow;
         sp<DisplaySurface> mDisplaySurface;
         std::unique_ptr<RE::Surface> mRenderSurface;
diff --git a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
index 267670a..b9e0715 100644
--- a/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
+++ b/services/surfaceflinger/tests/unittests/mock/DisplayHardware/MockComposer.h
@@ -74,9 +74,10 @@
     MOCK_METHOD2(getDisplayType, Error(Display, IComposerClient::DisplayType*));
     MOCK_METHOD2(getDozeSupport, Error(Display, bool*));
     MOCK_METHOD5(getHdrCapabilities, Error(Display, std::vector<Hdr>*, float*, float*, float*));
-    MOCK_METHOD2(getPerFrameMetadataKeys,
-                 Error(Display, std::vector<IComposerClient::PerFrameMetadataKey>*));
+    MOCK_METHOD1(getPerFrameMetadataKeys,
+                 std::vector<IComposerClient::PerFrameMetadataKey>(Display));
     MOCK_METHOD2(getDataspaceSaturationMatrix, Error(Dataspace, mat4*));
+    MOCK_METHOD3(getDisplayIdentificationData, Error(Display, uint8_t*, std::vector<uint8_t>*));
     MOCK_METHOD3(getReleaseFences, Error(Display, std::vector<Layer>*, std::vector<int>*));
     MOCK_METHOD2(presentDisplay, Error(Display, int*));
     MOCK_METHOD2(setActiveConfig, Error(Display, Config));
diff --git a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
index e6ea663..df9bfc6 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockEventThread.h
@@ -31,7 +31,7 @@
     MOCK_CONST_METHOD0(createEventConnection, sp<BnDisplayEventConnection>());
     MOCK_METHOD0(onScreenReleased, void());
     MOCK_METHOD0(onScreenAcquired, void());
-    MOCK_METHOD2(onHotplugReceived, void(int, bool));
+    MOCK_METHOD2(onHotplugReceived, void(DisplayType, bool));
     MOCK_CONST_METHOD1(dump, void(String8&));
     MOCK_METHOD1(setPhaseOffset, void(nsecs_t phaseOffset));
 };
diff --git a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
index ac08293..7caf864 100644
--- a/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
+++ b/services/surfaceflinger/tests/unittests/mock/RenderEngine/MockRenderEngine.h
@@ -37,7 +37,6 @@
     MOCK_METHOD0(createImage, std::unique_ptr<RE::Image>());
     MOCK_CONST_METHOD0(primeCache, void());
     MOCK_METHOD1(dump, void(String8&));
-    MOCK_CONST_METHOD0(supportsImageCrop, bool());
     MOCK_CONST_METHOD0(isCurrent, bool());
     MOCK_METHOD1(setCurrentSurface, bool(const RE::Surface&));
     MOCK_METHOD0(resetCurrentSurface, void());
@@ -98,9 +97,8 @@
     Image();
     ~Image() override;
 
-    MOCK_METHOD4(setNativeWindowBuffer,
-                 bool(ANativeWindowBuffer* buffer, bool isProtected, int32_t cropWidth,
-                      int32_t cropHeight));
+    MOCK_METHOD2(setNativeWindowBuffer,
+                 bool(ANativeWindowBuffer* buffer, bool isProtected));
 };
 
 } // namespace mock
diff --git a/services/vr/bufferhubd/detached_buffer_channel.cpp b/services/vr/bufferhubd/detached_buffer_channel.cpp
index a5cf68d..3061805 100644
--- a/services/vr/bufferhubd/detached_buffer_channel.cpp
+++ b/services/vr/bufferhubd/detached_buffer_channel.cpp
@@ -109,6 +109,7 @@
   return BufferDescription<BorrowedHandle>{buffer_,
                                            metadata_buffer_,
                                            buffer_id(),
+                                           channel_id(),
                                            /*buffer_state_bit=*/0,
                                            BorrowedHandle{},
                                            BorrowedHandle{}};
diff --git a/services/vr/bufferhubd/producer_channel.cpp b/services/vr/bufferhubd/producer_channel.cpp
index b6977aa..97af660 100644
--- a/services/vr/bufferhubd/producer_channel.cpp
+++ b/services/vr/bufferhubd/producer_channel.cpp
@@ -236,9 +236,13 @@
 
 BufferDescription<BorrowedHandle> ProducerChannel::GetBuffer(
     uint64_t buffer_state_bit) {
-  return {
-      buffer_,          metadata_buffer_,           buffer_id(),
-      buffer_state_bit, acquire_fence_fd_.Borrow(), release_fence_fd_.Borrow()};
+  return {buffer_,
+          metadata_buffer_,
+          buffer_id(),
+          channel_id(),
+          buffer_state_bit,
+          acquire_fence_fd_.Borrow(),
+          release_fence_fd_.Borrow()};
 }
 
 Status<BufferDescription<BorrowedHandle>> ProducerChannel::OnGetBuffer(
diff --git a/services/vr/bufferhubd/producer_channel.h b/services/vr/bufferhubd/producer_channel.h
index 67fdf15..10a4ce7 100644
--- a/services/vr/bufferhubd/producer_channel.h
+++ b/services/vr/bufferhubd/producer_channel.h
@@ -43,6 +43,8 @@
 
   ~ProducerChannel() override;
 
+  uint64_t buffer_state() const { return buffer_state_->load(); }
+
   bool HandleMessage(Message& message) override;
   void HandleImpulse(Message& message) override;
 
diff --git a/services/vr/bufferhubd/producer_queue_channel.cpp b/services/vr/bufferhubd/producer_queue_channel.cpp
index c0c48c2..88f5508 100644
--- a/services/vr/bufferhubd/producer_queue_channel.cpp
+++ b/services/vr/bufferhubd/producer_queue_channel.cpp
@@ -76,6 +76,11 @@
           message);
       return true;
 
+    case BufferHubRPC::ProducerQueueInsertBuffer::Opcode:
+      DispatchRemoteMethod<BufferHubRPC::ProducerQueueInsertBuffer>(
+          *this, &ProducerQueueChannel::OnProducerQueueInsertBuffer, message);
+      return true;
+
     case BufferHubRPC::ProducerQueueRemoveBuffer::Opcode:
       DispatchRemoteMethod<BufferHubRPC::ProducerQueueRemoveBuffer>(
           *this, &ProducerQueueChannel::OnProducerQueueRemoveBuffer, message);
@@ -278,6 +283,81 @@
   return {{std::move(buffer_handle), slot}};
 }
 
+Status<size_t> ProducerQueueChannel::OnProducerQueueInsertBuffer(
+    pdx::Message& message, int buffer_cid) {
+  ATRACE_NAME("ProducerQueueChannel::InsertBuffer");
+  ALOGD_IF(TRACE,
+           "ProducerQueueChannel::InsertBuffer: channel_id=%d, buffer_cid=%d",
+           channel_id(), buffer_cid);
+
+  if (capacity_ >= BufferHubRPC::kMaxQueueCapacity) {
+    ALOGE("ProducerQueueChannel::InsertBuffer: reaches kMaxQueueCapacity.");
+    return ErrorStatus(E2BIG);
+  }
+  auto producer_channel = std::static_pointer_cast<ProducerChannel>(
+      service()->GetChannel(buffer_cid));
+  if (producer_channel == nullptr ||
+      producer_channel->channel_type() != BufferHubChannel::kProducerType) {
+    // Rejects the request if the requested buffer channel is invalid and/or
+    // it's not a ProducerChannel.
+    ALOGE(
+        "ProducerQueueChannel::InsertBuffer: Invalid buffer_cid=%d, "
+        "producer_buffer=0x%p, channel_type=%d.",
+        buffer_cid, producer_channel.get(),
+        producer_channel == nullptr ? -1 : producer_channel->channel_type());
+    return ErrorStatus(EINVAL);
+  }
+  if (producer_channel->GetActiveProcessId() != message.GetProcessId()) {
+    // Rejects the request if the requested buffer channel is not currently
+    // connected to the caller this is IPC request. This effectively prevents
+    // fake buffer_cid from being injected.
+    ALOGE(
+        "ProducerQueueChannel::InsertBuffer: Requested buffer channel "
+        "(buffer_cid=%d) is not connected to the calling process (pid=%d). "
+        "It's connected to a different process (pid=%d).",
+        buffer_cid, message.GetProcessId(),
+        producer_channel->GetActiveProcessId());
+    return ErrorStatus(EINVAL);
+  }
+  uint64_t buffer_state = producer_channel->buffer_state();
+  if (!BufferHubDefs::IsBufferGained(buffer_state)) {
+    // Rejects the request if the requested buffer is not in Gained state.
+    ALOGE(
+        "ProducerQueueChannel::InsertBuffer: The buffer (cid=%d, "
+        "state=0x%" PRIx64 ") is not in gained state.",
+        buffer_cid, buffer_state);
+    return ErrorStatus(EINVAL);
+  }
+
+  // Register the to-be-inserted buffer's channel_id into the first empty
+  // buffer slot.
+  size_t slot = 0;
+  for (; slot < BufferHubRPC::kMaxQueueCapacity; slot++) {
+    if (buffers_[slot].expired())
+      break;
+  }
+  if (slot == BufferHubRPC::kMaxQueueCapacity) {
+    ALOGE(
+        "ProducerQueueChannel::AllocateBuffer: Cannot find empty slot for new "
+        "buffer allocation.");
+    return ErrorStatus(E2BIG);
+  }
+
+  buffers_[slot] = producer_channel;
+  capacity_++;
+
+  // Notify each consumer channel about the new buffer.
+  for (auto* consumer_channel : consumer_channels_) {
+    ALOGD(
+        "ProducerQueueChannel::AllocateBuffer: Notified consumer with new "
+        "buffer, buffer_cid=%d",
+        buffer_cid);
+    consumer_channel->RegisterNewBuffer(producer_channel, slot);
+  }
+
+  return {slot};
+}
+
 Status<void> ProducerQueueChannel::OnProducerQueueRemoveBuffer(
     Message& /*message*/, size_t slot) {
   if (buffers_[slot].expired()) {
diff --git a/services/vr/bufferhubd/producer_queue_channel.h b/services/vr/bufferhubd/producer_queue_channel.h
index e825f47..e4fa243 100644
--- a/services/vr/bufferhubd/producer_queue_channel.h
+++ b/services/vr/bufferhubd/producer_queue_channel.h
@@ -38,8 +38,12 @@
                                  uint32_t format, uint64_t usage,
                                  size_t buffer_count);
 
-  // Detach a BufferHubProducer indicated by |slot|. Note that the buffer must
-  // be in Gain'ed state for the producer queue to detach.
+  // Inserts a BufferProducer into the queue. Note that the buffer must be in
+  // Gain'ed state for the operation to succeed.
+  pdx::Status<size_t> OnProducerQueueInsertBuffer(pdx::Message& message, int buffer_cid);
+
+  // Removes a BufferProducer indicated by |slot|. Note that the buffer must be
+  // in Gain'ed state for the operation to succeed.
   pdx::Status<void> OnProducerQueueRemoveBuffer(pdx::Message& message,
                                                 size_t slot);
 
diff --git a/services/vr/hardware_composer/Android.bp b/services/vr/hardware_composer/Android.bp
index 90edf69..003775b 100644
--- a/services/vr/hardware_composer/Android.bp
+++ b/services/vr/hardware_composer/Android.bp
@@ -39,6 +39,10 @@
     "android.hardware.graphics.composer@2.1-hal",
   ],
 
+  export_static_lib_headers: [
+    "libdisplay",
+  ],
+
   export_shared_lib_headers: [
     "android.frameworks.vr.composer@1.0",
     "android.hardware.graphics.composer@2.1",
@@ -48,6 +52,7 @@
 
   cflags: [
     "-DLOG_TAG=\"vr_hwc\"",
+    "-DATRACE_TAG=ATRACE_TAG_GRAPHICS",
     "-Wall",
     "-Werror",
     // mVrClient unused in vr_composer_client.cpp
@@ -115,6 +120,7 @@
 
 cc_binary {
   name: "vr_hwc",
+  vintf_fragments: ["manifest_vr_hwc.xml"],
   srcs: [
     "vr_hardware_composer_service.cpp"
   ],
diff --git a/services/vr/hardware_composer/impl/vr_hwc.cpp b/services/vr/hardware_composer/impl/vr_hwc.cpp
index 4af47d2..d1ed12b 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.cpp
+++ b/services/vr/hardware_composer/impl/vr_hwc.cpp
@@ -16,9 +16,11 @@
 #include "impl/vr_hwc.h"
 
 #include "android-base/stringprintf.h"
+#include <binder/IServiceManager.h>
 #include <cutils/properties.h>
 #include <private/dvr/display_client.h>
 #include <ui/Fence.h>
+#include <utils/Trace.h>
 
 #include <mutex>
 
@@ -244,29 +246,38 @@
 ////////////////////////////////////////////////////////////////////////////////
 // VrHwcClient
 
-VrHwc::VrHwc() {}
+VrHwc::VrHwc() {
+  vsync_callback_ = new VsyncCallback;
+}
 
-VrHwc::~VrHwc() {}
+VrHwc::~VrHwc() {
+  vsync_callback_->SetEventCallback(nullptr);
+}
 
 bool VrHwc::hasCapability(hwc2_capability_t /* capability */) { return false; }
 
 void VrHwc::registerEventCallback(EventCallback* callback) {
-  {
-    std::lock_guard<std::mutex> guard(mutex_);
-    event_callback_ = callback;
-    int32_t width, height;
-    GetPrimaryDisplaySize(&width, &height);
-    // Create the primary display late to avoid initialization issues between
-    // VR HWC and SurfaceFlinger.
-    displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
-  }
+  std::unique_lock<std::mutex> lock(mutex_);
+  event_callback_ = callback;
+  int32_t width, height;
+  GetPrimaryDisplaySize(&width, &height);
+  // Create the primary display late to avoid initialization issues between
+  // VR HWC and SurfaceFlinger.
+  displays_[kDefaultDisplayId].reset(new HwcDisplay(width, height));
+
+  // Surface flinger will make calls back into vr_hwc when it receives the
+  // onHotplug() call, so it's important to release mutex_ here.
+  lock.unlock();
   event_callback_->onHotplug(kDefaultDisplayId,
                              IComposerCallback::Connection::CONNECTED);
+  lock.lock();
+  UpdateVsyncCallbackEnabledLocked();
 }
 
 void VrHwc::unregisterEventCallback() {
   std::lock_guard<std::mutex> guard(mutex_);
   event_callback_ = nullptr;
+  UpdateVsyncCallbackEnabledLocked();
 }
 
 uint32_t VrHwc::getMaxVirtualDisplayCount() { return 1; }
@@ -475,8 +486,45 @@
   if (!display_ptr)
     return Error::BAD_DISPLAY;
 
-  display_ptr->set_vsync_enabled(enabled);
-  return Error::NONE;
+  if (enabled != IComposerClient::Vsync::ENABLE &&
+      enabled != IComposerClient::Vsync::DISABLE) {
+    return Error::BAD_PARAMETER;
+  }
+
+  Error set_vsync_result = Error::NONE;
+  if (display == kDefaultDisplayId) {
+    sp<IVsyncService> vsync_service = interface_cast<IVsyncService>(
+        defaultServiceManager()->getService(
+            String16(IVsyncService::GetServiceName())));
+    if (vsync_service == nullptr) {
+      ALOGE("Failed to get vsync service");
+      return Error::NO_RESOURCES;
+    }
+
+    if (enabled == IComposerClient::Vsync::ENABLE) {
+      ALOGI("Enable vsync");
+      display_ptr->set_vsync_enabled(true);
+      status_t result = vsync_service->registerCallback(vsync_callback_);
+      if (result != OK) {
+        ALOGE("%s service registerCallback() failed: %s (%d)",
+            IVsyncService::GetServiceName(), strerror(-result), result);
+        set_vsync_result = Error::NO_RESOURCES;
+      }
+    } else if (enabled == IComposerClient::Vsync::DISABLE) {
+      ALOGI("Disable vsync");
+      display_ptr->set_vsync_enabled(false);
+      status_t result = vsync_service->unregisterCallback(vsync_callback_);
+      if (result != OK) {
+        ALOGE("%s service unregisterCallback() failed: %s (%d)",
+            IVsyncService::GetServiceName(), strerror(-result), result);
+        set_vsync_result = Error::NO_RESOURCES;
+      }
+    }
+
+    UpdateVsyncCallbackEnabledLocked();
+  }
+
+  return set_vsync_result;
 }
 
 Error VrHwc::setColorTransform(Display display, const float* matrix,
@@ -559,7 +607,8 @@
   frame.display_height = display_ptr->height();
   frame.active_config = display_ptr->active_config();
   frame.power_mode = display_ptr->power_mode();
-  frame.vsync_enabled = display_ptr->vsync_enabled();
+  frame.vsync_enabled = display_ptr->vsync_enabled() ?
+      IComposerClient::Vsync::ENABLE : IComposerClient::Vsync::DISABLE;
   frame.color_transform_hint = display_ptr->color_transform_hint();
   frame.color_mode = display_ptr->color_mode();
   memcpy(frame.color_transform, display_ptr->color_transform(),
@@ -911,6 +960,15 @@
   return iter == displays_.end() ? nullptr : iter->second.get();
 }
 
+void VrHwc::UpdateVsyncCallbackEnabledLocked() {
+  auto primary_display = FindDisplay(kDefaultDisplayId);
+  LOG_ALWAYS_FATAL_IF(event_callback_ != nullptr && primary_display == nullptr,
+      "Should have created the primary display by now");
+  bool send_vsync =
+      event_callback_ != nullptr && primary_display->vsync_enabled();
+  vsync_callback_->SetEventCallback(send_vsync ? event_callback_ : nullptr);
+}
+
 void HwcLayer::dumpDebugInfo(std::string* result) const {
   if (!result) {
     return;
@@ -928,5 +986,18 @@
       buffer_metadata.layerCount, buffer_metadata.format);
 }
 
+status_t VrHwc::VsyncCallback::onVsync(int64_t vsync_timestamp) {
+  ATRACE_NAME("vr_hwc onVsync");
+  std::lock_guard<std::mutex> guard(mutex_);
+  if (callback_ != nullptr)
+    callback_->onVsync(kDefaultDisplayId, vsync_timestamp);
+  return NO_ERROR;
+}
+
+void VrHwc::VsyncCallback::SetEventCallback(EventCallback* callback) {
+  std::lock_guard<std::mutex> guard(mutex_);
+  callback_ = callback;
+}
+
 }  // namespace dvr
 }  // namespace android
diff --git a/services/vr/hardware_composer/impl/vr_hwc.h b/services/vr/hardware_composer/impl/vr_hwc.h
index 85e587a..f9872b2 100644
--- a/services/vr/hardware_composer/impl/vr_hwc.h
+++ b/services/vr/hardware_composer/impl/vr_hwc.h
@@ -20,6 +20,7 @@
 #include <android/frameworks/vr/composer/1.0/IVrComposerClient.h>
 #include <android/hardware/graphics/composer/2.1/IComposer.h>
 #include <composer-hal/2.1/ComposerHal.h>
+#include <private/dvr/vsync_service.h>
 #include <ui/Fence.h>
 #include <ui/GraphicBuffer.h>
 #include <utils/StrongPointer.h>
@@ -156,10 +157,8 @@
   IComposerClient::PowerMode power_mode() const { return power_mode_; }
   void set_power_mode(IComposerClient::PowerMode mode) { power_mode_ = mode; }
 
-  IComposerClient::Vsync vsync_enabled() const { return vsync_enabled_; }
-  void set_vsync_enabled(IComposerClient::Vsync vsync) {
-    vsync_enabled_ = vsync;
-  }
+  bool vsync_enabled() const { return vsync_enabled_; }
+  void set_vsync_enabled(bool vsync) {vsync_enabled_ = vsync;}
 
   const float* color_transform() const { return color_transform_; }
   int32_t color_transform_hint() const { return color_transform_hint_; }
@@ -187,7 +186,7 @@
   Config active_config_;
   ColorMode color_mode_;
   IComposerClient::PowerMode power_mode_;
-  IComposerClient::Vsync vsync_enabled_;
+  bool vsync_enabled_ = false;
   float color_transform_[16];
   int32_t color_transform_hint_;
 
@@ -299,8 +298,23 @@
   void UnregisterObserver(Observer* observer) override;
 
  private:
+  class VsyncCallback : public BnVsyncCallback {
+   public:
+    status_t onVsync(int64_t vsync_timestamp) override;
+    void SetEventCallback(EventCallback* callback);
+   private:
+    std::mutex mutex_;
+    EventCallback* callback_;
+  };
+
   HwcDisplay* FindDisplay(Display display);
 
+  // Re-evaluate whether or not we should start making onVsync() callbacks to
+  // the client. We need enableCallback(true) to have been called, and
+  // setVsyncEnabled() to have been called for the primary display. The caller
+  // must have mutex_ locked already.
+  void UpdateVsyncCallbackEnabledLocked();
+
   wp<VrComposerClient> client_;
 
   // Guard access to internal state from binder threads.
@@ -312,6 +326,8 @@
   EventCallback* event_callback_ = nullptr;
   Observer* observer_ = nullptr;
 
+  sp<VsyncCallback> vsync_callback_;
+
   VrHwc(const VrHwc&) = delete;
   void operator=(const VrHwc&) = delete;
 };
diff --git a/services/vr/hardware_composer/manifest_vr_hwc.xml b/services/vr/hardware_composer/manifest_vr_hwc.xml
new file mode 100644
index 0000000..1068cac
--- /dev/null
+++ b/services/vr/hardware_composer/manifest_vr_hwc.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="framework">
+    <hal>
+      <name>android.hardware.graphics.composer</name>
+      <transport>hwbinder</transport>
+      <version>2.1</version>
+      <interface>
+          <name>IComposer</name>
+          <instance>vr</instance>
+      </interface>
+    </hal>
+</manifest>
diff --git a/services/vr/performanced/performance_service.cpp b/services/vr/performanced/performance_service.cpp
index 4c26671..d304bac 100644
--- a/services/vr/performanced/performance_service.cpp
+++ b/services/vr/performanced/performance_service.cpp
@@ -124,9 +124,6 @@
   // TODO(eieio): Replace this witha device-specific config file. This is just a
   // hack for now to put some form of permission logic in place while a longer
   // term solution is developed.
-  using AllowRootSystem =
-      CheckAnd<SameProcess,
-               CheckOr<UserId<AID_ROOT, AID_SYSTEM>, GroupId<AID_SYSTEM>>>;
   using AllowRootSystemGraphics =
       CheckAnd<SameProcess, CheckOr<UserId<AID_ROOT, AID_SYSTEM, AID_GRAPHICS>,
                                     GroupId<AID_SYSTEM, AID_GRAPHICS>>>;
@@ -170,17 +167,17 @@
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
         .priority = fifo_low,
-        .permission_check = AllowRootSystem::Check}},
+        .permission_check = AllowRootSystemTrusted::Check}},
       {"sensors:low",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
         .priority = fifo_low,
-        .permission_check = AllowRootSystem::Check}},
+        .permission_check = AllowRootSystemTrusted::Check}},
       {"sensors:high",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
         .priority = fifo_low + 1,
-        .permission_check = AllowRootSystem::Check}},
+        .permission_check = AllowRootSystemTrusted::Check}},
       {"vr:system:arp",
        {.timer_slack = kTimerSlackForegroundNs,
         .scheduler_policy = SCHED_FIFO | SCHED_RESET_ON_FORK,
diff --git a/vulkan/libvulkan/Android.bp b/vulkan/libvulkan/Android.bp
index cbba5f4..7eaf7b2 100644
--- a/vulkan/libvulkan/Android.bp
+++ b/vulkan/libvulkan/Android.bp
@@ -81,6 +81,8 @@
         "libutils",
         "libcutils",
         "libz",
+        "libnativebridge",
+        "libnativeloader",
         "libnativewindow",
         "android.hardware.graphics.common@1.0",
     ],
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index 56bc35e..4c2d223 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -984,7 +984,7 @@
     uint32_t icd_api_version;
     PFN_vkEnumerateInstanceVersion pfn_enumerate_instance_version =
         reinterpret_cast<PFN_vkEnumerateInstanceVersion>(
-            Hal::Device().GetInstanceProcAddr(NULL,
+            Hal::Device().GetInstanceProcAddr(nullptr,
                                               "vkEnumerateInstanceVersion"));
     if (!pfn_enumerate_instance_version) {
         icd_api_version = VK_API_VERSION_1_0;
diff --git a/vulkan/libvulkan/layers_extensions.cpp b/vulkan/libvulkan/layers_extensions.cpp
index 3a59208..96c5563 100644
--- a/vulkan/libvulkan/layers_extensions.cpp
+++ b/vulkan/libvulkan/layers_extensions.cpp
@@ -31,6 +31,8 @@
 #include <cutils/properties.h>
 #include <graphicsenv/GraphicsEnv.h>
 #include <log/log.h>
+#include <nativebridge/native_bridge.h>
+#include <nativeloader/native_loader.h>
 #include <ziparchive/zip_archive.h>
 
 // TODO(jessehall): The whole way we deal with extensions is pretty hokey, and
@@ -73,12 +75,14 @@
         : path_(path),
           filename_(filename),
           dlhandle_(nullptr),
+          native_bridge_(false),
           refcount_(0) {}
 
     LayerLibrary(LayerLibrary&& other)
         : path_(std::move(other.path_)),
           filename_(std::move(other.filename_)),
           dlhandle_(other.dlhandle_),
+          native_bridge_(other.native_bridge_),
           refcount_(other.refcount_) {
         other.dlhandle_ = nullptr;
         other.refcount_ = 0;
@@ -101,6 +105,17 @@
     const std::string GetFilename() { return filename_; }
 
    private:
+    // TODO(b/79940628): remove that adapter when we could use NativeBridgeGetTrampoline
+    // for native libraries.
+    template<typename Func = void*>
+    Func GetTrampoline(const char* name) const {
+        if (native_bridge_) {
+            return reinterpret_cast<Func>(android::NativeBridgeGetTrampoline(
+                dlhandle_, name, nullptr, 0));
+        }
+        return reinterpret_cast<Func>(dlsym(dlhandle_, name));
+    }
+
     const std::string path_;
 
     // Track the filename alone so we can detect duplicates
@@ -108,6 +123,7 @@
 
     std::mutex mutex_;
     void* dlhandle_;
+    bool native_bridge_;
     size_t refcount_;
 };
 
@@ -123,19 +139,23 @@
         auto app_namespace = android::GraphicsEnv::getInstance().getAppNamespace();
         if (app_namespace &&
             !android::base::StartsWith(path_, kSystemLayerLibraryDir)) {
-            android_dlextinfo dlextinfo = {};
-            dlextinfo.flags = ANDROID_DLEXT_USE_NAMESPACE;
-            dlextinfo.library_namespace = app_namespace;
-            dlhandle_ = android_dlopen_ext(path_.c_str(), RTLD_NOW | RTLD_LOCAL,
-                                           &dlextinfo);
+            std::string error_msg;
+            dlhandle_ = OpenNativeLibrary(
+                app_namespace, path_.c_str(), &native_bridge_, &error_msg);
+            if (!dlhandle_) {
+                ALOGE("failed to load layer library '%s': %s", path_.c_str(),
+                      error_msg.c_str());
+                refcount_ = 0;
+                return false;
+            }
         } else {
-            dlhandle_ = dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL);
-        }
-        if (!dlhandle_) {
-            ALOGE("failed to load layer library '%s': %s", path_.c_str(),
-                  dlerror());
-            refcount_ = 0;
-            return false;
+          dlhandle_ = dlopen(path_.c_str(), RTLD_NOW | RTLD_LOCAL);
+            if (!dlhandle_) {
+                ALOGE("failed to load layer library '%s': %s", path_.c_str(),
+                      dlerror());
+                refcount_ = 0;
+                return false;
+            }
         }
     }
     return true;
@@ -153,11 +173,11 @@
 bool LayerLibrary::EnumerateLayers(size_t library_idx,
                                    std::vector<Layer>& instance_layers) const {
     PFN_vkEnumerateInstanceLayerProperties enumerate_instance_layers =
-        reinterpret_cast<PFN_vkEnumerateInstanceLayerProperties>(
-            dlsym(dlhandle_, "vkEnumerateInstanceLayerProperties"));
+        GetTrampoline<PFN_vkEnumerateInstanceLayerProperties>(
+            "vkEnumerateInstanceLayerProperties");
     PFN_vkEnumerateInstanceExtensionProperties enumerate_instance_extensions =
-        reinterpret_cast<PFN_vkEnumerateInstanceExtensionProperties>(
-            dlsym(dlhandle_, "vkEnumerateInstanceExtensionProperties"));
+        GetTrampoline<PFN_vkEnumerateInstanceExtensionProperties>(
+            "vkEnumerateInstanceExtensionProperties");
     if (!enumerate_instance_layers || !enumerate_instance_extensions) {
         ALOGE("layer library '%s' missing some instance enumeration functions",
               path_.c_str());
@@ -166,11 +186,11 @@
 
     // device functions are optional
     PFN_vkEnumerateDeviceLayerProperties enumerate_device_layers =
-        reinterpret_cast<PFN_vkEnumerateDeviceLayerProperties>(
-            dlsym(dlhandle_, "vkEnumerateDeviceLayerProperties"));
+        GetTrampoline<PFN_vkEnumerateDeviceLayerProperties>(
+            "vkEnumerateDeviceLayerProperties");
     PFN_vkEnumerateDeviceExtensionProperties enumerate_device_extensions =
-        reinterpret_cast<PFN_vkEnumerateDeviceExtensionProperties>(
-            dlsym(dlhandle_, "vkEnumerateDeviceExtensionProperties"));
+        GetTrampoline<PFN_vkEnumerateDeviceExtensionProperties>(
+            "vkEnumerateDeviceExtensionProperties");
 
     // get layer counts
     uint32_t num_instance_layers = 0;
@@ -301,10 +321,10 @@
     char* name = static_cast<char*>(alloca(layer_name_len + gpa_name_len + 1));
     strcpy(name, layer.properties.layerName);
     strcpy(name + layer_name_len, gpa_name);
-    if (!(gpa = dlsym(dlhandle_, name))) {
+    if (!(gpa = GetTrampoline(name))) {
         strcpy(name, "vk");
         strcpy(name + 2, gpa_name);
-        gpa = dlsym(dlhandle_, name);
+        gpa = GetTrampoline(name);
     }
     return gpa;
 }
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 3db8a39..915de45 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -335,15 +335,15 @@
             swapchain.surface.window.get(), ti.native_frame_id_,
             &desired_present_time, &render_complete_time,
             &composition_latch_time,
-            NULL,  //&first_composition_start_time,
-            NULL,  //&last_composition_start_time,
-            NULL,  //&composition_finish_time,
+            nullptr,  //&first_composition_start_time,
+            nullptr,  //&last_composition_start_time,
+            nullptr,  //&composition_finish_time,
             // TODO(ianelliott): Maybe ask if this one is
             // supported, at startup time (since it may not be
             // supported):
             &actual_present_time,
-            NULL,  //&dequeue_ready_time,
-            NULL /*&reads_done_time*/);
+            nullptr,  //&dequeue_ready_time,
+            nullptr /*&reads_done_time*/);
 
         if (ret != android::NO_ERROR) {
             continue;
@@ -575,15 +575,10 @@
             break;
     }
 
-    // USAGE_CPU_READ_MASK 0xFUL
-    // USAGE_CPU_WRITE_MASK (0xFUL << 4)
-    // The currently used bits are as below:
-    // USAGE_CPU_READ_RARELY = 2UL
-    // USAGE_CPU_READ_OFTEN = 3UL
-    // USAGE_CPU_WRITE_RARELY = (2UL << 4)
-    // USAGE_CPU_WRITE_OFTEN = (3UL << 4)
-    *supported = static_cast<VkBool32>(format_supported ||
-                                       (surface->consumer_usage & 0xFFUL) == 0);
+    *supported = static_cast<VkBool32>(
+        format_supported || (surface->consumer_usage &
+                             (AHARDWAREBUFFER_USAGE_CPU_READ_MASK |
+                              AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) == 0);
 
     return VK_SUCCESS;
 }
diff --git a/vulkan/vkjson/Android.bp b/vulkan/vkjson/Android.bp
index e387165..7fbe315 100644
--- a/vulkan/vkjson/Android.bp
+++ b/vulkan/vkjson/Android.bp
@@ -9,7 +9,6 @@
         "-Werror",
     ],
     cppflags: [
-        "-std=c++11",
         "-Wno-sign-compare",
     ],
     export_include_dirs: [
@@ -35,7 +34,6 @@
         "-Werror",
     ],
     cppflags: [
-        "-std=c++11",
         "-Wno-sign-compare",
     ],
     export_include_dirs: [