Merge changes Icf7cf2fd,I325521b7,Ia80c865d,I73599f62,I8526e671, ... into pi-dev am: 2afd5172c3
am: 2e4946ed0f

Change-Id: I14c1e9d96b261f3afc1da31ebfe5e03b5ff9e8a1
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 9648ede..6e0578c 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -918,53 +918,6 @@
     RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"});
 }
 
-static void AddGlobalAnrTraceFile(const bool add_to_zip, const std::string& anr_traces_file,
-                                  const std::string& anr_traces_dir) {
-    std::string dump_traces_dir;
-
-    if (dump_traces_path != nullptr) {
-        if (add_to_zip) {
-            dump_traces_dir = dirname(dump_traces_path);
-            MYLOGD("Adding ANR traces (directory %s) to the zip file\n", dump_traces_dir.c_str());
-            ds.AddDir(dump_traces_dir, true);
-        } else {
-            MYLOGD("Dumping current ANR traces (%s) to the main bugreport entry\n",
-                   dump_traces_path);
-            ds.DumpFile("VM TRACES JUST NOW", dump_traces_path);
-        }
-    }
-
-
-    // Make sure directory is not added twice.
-    // TODO: this is an overzealous check because it's relying on dump_traces_path - which is
-    // generated by dump_traces() -  and anr_traces_path - which is retrieved from a system
-    // property - but in reality they're the same path (although the former could be nullptr).
-    // Anyways, once dump_traces() is refactored as a private Dumpstate function, this logic should
-    // be revisited.
-    bool already_dumped = anr_traces_dir == dump_traces_dir;
-
-    MYLOGD("AddGlobalAnrTraceFile(): dump_traces_dir=%s, anr_traces_dir=%s, already_dumped=%d\n",
-           dump_traces_dir.c_str(), anr_traces_dir.c_str(), already_dumped);
-
-    android::base::unique_fd fd(TEMP_FAILURE_RETRY(
-        open(anr_traces_file.c_str(), O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK)));
-    if (fd.get() < 0) {
-        printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_file.c_str(), strerror(errno));
-    } else {
-        if (add_to_zip) {
-            if (!already_dumped) {
-                MYLOGD("Adding dalvik ANR traces (directory %s) to the zip file\n",
-                       anr_traces_dir.c_str());
-                ds.AddDir(anr_traces_dir, true);
-            }
-        } else {
-            MYLOGD("Dumping last ANR traces (%s) to the main bugreport entry\n",
-                   anr_traces_file.c_str());
-            dump_file_from_fd("VM TRACES AT LAST ANR", anr_traces_file.c_str(), fd.get());
-        }
-    }
-}
-
 static void AddAnrTraceDir(const bool add_to_zip, const std::string& anr_traces_dir) {
     MYLOGD("AddAnrTraceDir(): dump_traces_file=%s, anr_traces_dir=%s\n", dump_traces_path,
            anr_traces_dir.c_str());
@@ -1007,50 +960,22 @@
 static void AddAnrTraceFiles() {
     const bool add_to_zip = ds.IsZipping() && ds.version_ == VERSION_SPLIT_ANR;
 
-    std::string anr_traces_file;
-    std::string anr_traces_dir;
-    bool is_global_trace_file = true;
+    std::string anr_traces_dir = "/data/anr";
 
-    // First check whether the stack-trace-dir property is set. When it's set,
-    // each ANR trace will be written to a separate file and not to a global
-    // stack trace file.
-    anr_traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", "");
-    if (anr_traces_dir.empty()) {
-        anr_traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
-        if (!anr_traces_file.empty()) {
-            anr_traces_dir = dirname(anr_traces_file.c_str());
-        }
-    } else {
-        is_global_trace_file = false;
-    }
+    AddAnrTraceDir(add_to_zip, anr_traces_dir);
 
-    // We have neither configured a global trace file nor a trace directory,
-    // there will be nothing to dump.
-    if (anr_traces_file.empty() && anr_traces_dir.empty()) {
-        printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
-        return;
-    }
-
-    if (is_global_trace_file) {
-        AddGlobalAnrTraceFile(add_to_zip, anr_traces_file, anr_traces_dir);
-    } else {
-        AddAnrTraceDir(add_to_zip, anr_traces_dir);
-    }
-
-    /* slow traces for slow operations */
+    // Slow traces for slow operations.
     struct stat st;
-    if (!anr_traces_dir.empty()) {
-        int i = 0;
-        while (true) {
-            const std::string slow_trace_path =
-                anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
-            if (stat(slow_trace_path.c_str(), &st)) {
-                // No traces file at this index, done with the files.
-                break;
-            }
-            ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
-            i++;
+    int i = 0;
+    while (true) {
+        const std::string slow_trace_path =
+            anr_traces_dir + android::base::StringPrintf("slow%02d.txt", i);
+        if (stat(slow_trace_path.c_str(), &st)) {
+            // No traces file at this index, done with the files.
+            break;
         }
+        ds.DumpFile("VM TRACES WHEN SLOW", slow_trace_path.c_str());
+        i++;
     }
 }
 
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 022f4fc..9beff98 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -779,29 +779,11 @@
     _redirect_to_file(redirect, path, O_APPEND);
 }
 
-const char* DumpTraces(const std::string& traces_path);
-const char* DumpTracesTombstoned(const std::string& traces_dir);
-
-/* dump Dalvik and native stack traces, return the trace file location (NULL if none) */
-const char *dump_traces() {
+// Dump Dalvik and native stack traces, return the trace file location (nullptr if none).
+const char* dump_traces() {
     DurationReporter duration_reporter("DUMP TRACES");
 
-    const std::string traces_dir = android::base::GetProperty("dalvik.vm.stack-trace-dir", "");
-    if (!traces_dir.empty()) {
-        return DumpTracesTombstoned(traces_dir);
-    }
-
-    const std::string traces_file = android::base::GetProperty("dalvik.vm.stack-trace-file", "");
-    if (!traces_file.empty()) {
-        return DumpTraces(traces_file);
-    }
-
-    return nullptr;
-}
-
-const char* DumpTracesTombstoned(const std::string& traces_dir) {
-    const std::string temp_file_pattern = traces_dir + "/dumptrace_XXXXXX";
-
+    const std::string temp_file_pattern = "/data/anr/dumptrace_XXXXXX";
     const size_t buf_size = temp_file_pattern.length() + 1;
     std::unique_ptr<char[]> file_name_buf(new char[buf_size]);
     memcpy(file_name_buf.get(), temp_file_pattern.c_str(), buf_size);
@@ -902,156 +884,6 @@
     return file_name_buf.release();
 }
 
-const char* DumpTraces(const std::string& traces_path) {
-    const char* result = NULL;
-    /* move the old traces.txt (if any) out of the way temporarily */
-    std::string anrtraces_path = traces_path + ".anr";
-    if (rename(traces_path.c_str(), anrtraces_path.c_str()) && errno != ENOENT) {
-        MYLOGE("rename(%s, %s): %s\n", traces_path.c_str(), anrtraces_path.c_str(), strerror(errno));
-        return nullptr;  // Can't rename old traces.txt -- no permission? -- leave it alone instead
-    }
-
-    /* create a new, empty traces.txt file to receive stack dumps */
-    int fd = TEMP_FAILURE_RETRY(
-        open(traces_path.c_str(), O_CREAT | O_WRONLY | O_APPEND | O_TRUNC | O_NOFOLLOW | O_CLOEXEC,
-             0666)); /* -rw-rw-rw- */
-    if (fd < 0) {
-        MYLOGE("%s: %s\n", traces_path.c_str(), strerror(errno));
-        return nullptr;
-    }
-    int chmod_ret = fchmod(fd, 0666);
-    if (chmod_ret < 0) {
-        MYLOGE("fchmod on %s failed: %s\n", traces_path.c_str(), strerror(errno));
-        close(fd);
-        return nullptr;
-    }
-
-    /* Variables below must be initialized before 'goto' statements */
-    int dalvik_found = 0;
-    int ifd, wfd = -1;
-    std::set<int> hal_pids = get_interesting_hal_pids();
-
-    /* walk /proc and kill -QUIT all Dalvik processes */
-    DIR *proc = opendir("/proc");
-    if (proc == NULL) {
-        MYLOGE("/proc: %s\n", strerror(errno));
-        goto error_close_fd;
-    }
-
-    /* use inotify to find when processes are done dumping */
-    ifd = inotify_init();
-    if (ifd < 0) {
-        MYLOGE("inotify_init: %s\n", strerror(errno));
-        goto error_close_fd;
-    }
-
-    wfd = inotify_add_watch(ifd, traces_path.c_str(), IN_CLOSE_WRITE);
-    if (wfd < 0) {
-        MYLOGE("inotify_add_watch(%s): %s\n", traces_path.c_str(), strerror(errno));
-        goto error_close_ifd;
-    }
-
-    struct dirent *d;
-    while ((d = readdir(proc))) {
-        int pid = atoi(d->d_name);
-        if (pid <= 0) continue;
-
-        char path[PATH_MAX];
-        char data[PATH_MAX];
-        snprintf(path, sizeof(path), "/proc/%d/exe", pid);
-        ssize_t len = readlink(path, data, sizeof(data) - 1);
-        if (len <= 0) {
-            continue;
-        }
-        data[len] = '\0';
-
-        if (!strncmp(data, "/system/bin/app_process", strlen("/system/bin/app_process"))) {
-            /* skip zygote -- it won't dump its stack anyway */
-            snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
-            int cfd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_CLOEXEC));
-            len = read(cfd, data, sizeof(data) - 1);
-            close(cfd);
-            if (len <= 0) {
-                continue;
-            }
-            data[len] = '\0';
-            if (!strncmp(data, "zygote", strlen("zygote"))) {
-                continue;
-            }
-
-            ++dalvik_found;
-            uint64_t start = Nanotime();
-            if (kill(pid, SIGQUIT)) {
-                MYLOGE("kill(%d, SIGQUIT): %s\n", pid, strerror(errno));
-                continue;
-            }
-
-            /* wait for the writable-close notification from inotify */
-            struct pollfd pfd = { ifd, POLLIN, 0 };
-            int ret = poll(&pfd, 1, TRACE_DUMP_TIMEOUT_MS);
-            if (ret < 0) {
-                MYLOGE("poll: %s\n", strerror(errno));
-            } else if (ret == 0) {
-                MYLOGE("warning: timed out dumping pid %d\n", pid);
-            } else {
-                struct inotify_event ie;
-                read(ifd, &ie, sizeof(ie));
-            }
-
-            if (lseek(fd, 0, SEEK_END) < 0) {
-                MYLOGE("lseek: %s\n", strerror(errno));
-            } else {
-                dprintf(fd, "[dump dalvik stack %d: %.3fs elapsed]\n", pid,
-                        (float)(Nanotime() - start) / NANOS_PER_SEC);
-            }
-        } else if (should_dump_native_traces(data) ||
-                   hal_pids.find(pid) != hal_pids.end()) {
-            /* dump native process if appropriate */
-            if (lseek(fd, 0, SEEK_END) < 0) {
-                MYLOGE("lseek: %s\n", strerror(errno));
-            } else {
-                static uint16_t timeout_failures = 0;
-                uint64_t start = Nanotime();
-
-                /* If 3 backtrace dumps fail in a row, consider debuggerd dead. */
-                if (timeout_failures == 3) {
-                    dprintf(fd, "too many stack dump failures, skipping...\n");
-                } else if (dump_backtrace_to_file_timeout(
-                        pid, kDebuggerdNativeBacktrace, 20, fd) == -1) {
-                    dprintf(fd, "dumping failed, likely due to a timeout\n");
-                    timeout_failures++;
-                } else {
-                    timeout_failures = 0;
-                }
-                dprintf(fd, "[dump native stack %d: %.3fs elapsed]\n", pid,
-                        (float)(Nanotime() - start) / NANOS_PER_SEC);
-            }
-        }
-    }
-
-    if (dalvik_found == 0) {
-        MYLOGE("Warning: no Dalvik processes found to dump stacks\n");
-    }
-
-    static std::string dumptraces_path = android::base::StringPrintf(
-        "%s/bugreport-%s", dirname(traces_path.c_str()), basename(traces_path.c_str()));
-    if (rename(traces_path.c_str(), dumptraces_path.c_str())) {
-        MYLOGE("rename(%s, %s): %s\n", traces_path.c_str(), dumptraces_path.c_str(),
-               strerror(errno));
-        goto error_close_ifd;
-    }
-    result = dumptraces_path.c_str();
-
-    /* replace the saved [ANR] traces.txt file */
-    rename(anrtraces_path.c_str(), traces_path.c_str());
-
-error_close_ifd:
-    close(ifd);
-error_close_fd:
-    close(fd);
-    return result;
-}
-
 void dump_route_tables() {
     DurationReporter duration_reporter("DUMP ROUTE TABLES");
     if (PropertiesHelper::IsDryRun()) return;
diff --git a/include/input/Input.h b/include/input/Input.h
index cfcafab..15c86eb 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -339,7 +339,7 @@
 
     static const char* getLabel(int32_t keyCode);
     static int32_t getKeyCodeFromLabel(const char* label);
-    
+
     void initialize(
             int32_t deviceId,
             int32_t source,
@@ -373,6 +373,10 @@
 
     virtual int32_t getType() const { return AINPUT_EVENT_TYPE_MOTION; }
 
+    inline int32_t getDisplayId() const { return mDisplayId; }
+
+    inline void setDisplayId(int32_t displayId) { mDisplayId = displayId; }
+
     inline int32_t getAction() const { return mAction; }
 
     inline int32_t getActionMasked() const { return mAction & AMOTION_EVENT_ACTION_MASK; }
@@ -556,6 +560,7 @@
     void initialize(
             int32_t deviceId,
             int32_t source,
+            int32_t displayId,
             int32_t action,
             int32_t actionButton,
             int32_t flags,
@@ -609,6 +614,7 @@
     static int32_t getAxisFromLabel(const char* label);
 
 protected:
+    int32_t mDisplayId;
     int32_t mAction;
     int32_t mActionButton;
     int32_t mFlags;
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 1ea2c2c..ee52661 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -64,7 +64,6 @@
             nsecs_t eventTime __attribute__((aligned(8)));
             int32_t deviceId;
             int32_t source;
-            int32_t displayId;
             int32_t action;
             int32_t flags;
             int32_t keyCode;
@@ -305,7 +304,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 +459,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/libs/input/Input.cpp b/libs/input/Input.cpp
index a624663..db27e11 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -215,6 +215,7 @@
 void MotionEvent::initialize(
         int32_t deviceId,
         int32_t source,
+        int32_t displayId,
         int32_t action,
         int32_t actionButton,
         int32_t flags,
@@ -231,6 +232,7 @@
         const PointerProperties* pointerProperties,
         const PointerCoords* pointerCoords) {
     InputEvent::initialize(deviceId, source);
+    mDisplayId = displayId;
     mAction = action;
     mActionButton = actionButton;
     mFlags = flags;
@@ -251,6 +253,7 @@
 
 void MotionEvent::copyFrom(const MotionEvent* other, bool keepHistory) {
     InputEvent::initialize(other->mDeviceId, other->mSource);
+    mDisplayId = other->mDisplayId;
     mAction = other->mAction;
     mActionButton = other->mActionButton;
     mFlags = other->mFlags;
@@ -431,6 +434,7 @@
 
     mDeviceId = parcel->readInt32();
     mSource = parcel->readInt32();
+    mDisplayId = parcel->readInt32();
     mAction = parcel->readInt32();
     mActionButton = parcel->readInt32();
     mFlags = parcel->readInt32();
@@ -480,6 +484,7 @@
 
     parcel->writeInt32(mDeviceId);
     parcel->writeInt32(mSource);
+    parcel->writeInt32(mDisplayId);
     parcel->writeInt32(mAction);
     parcel->writeInt32(mActionButton);
     parcel->writeInt32(mFlags);
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index aa0bf17..f1c3fea 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -303,13 +303,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) {
@@ -398,8 +400,7 @@
 }
 
 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);
@@ -407,7 +408,6 @@
 
     *outSeq = 0;
     *outEvent = NULL;
-    *displayId = -1;  // Invalid display.
 
     // Fetch the next input message.
     // Loop until an event can be returned or no additional events are received.
@@ -422,7 +422,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 +466,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 +500,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 +518,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,7 +538,7 @@
             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);
@@ -557,7 +556,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 +571,6 @@
             mSeqChains.push(seqChain);
             addSample(motionEvent, &msg);
         } else {
-            *displayId = msg.body.motion.displayId;
             initializeMotionEvent(motionEvent, &msg);
         }
         chain = msg.body.motion.seq;
@@ -950,6 +948,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/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index fd3b7c8..c4b8fe3 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() { }
@@ -248,7 +251,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 +304,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 +438,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 +566,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..6c4faed 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -89,9 +89,7 @@
 
     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";
 
@@ -131,23 +129,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 = 0;
+    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,8 +174,7 @@
 
     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";
 
@@ -190,6 +187,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/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index d19f3b8..77cce7a 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -38,14 +38,13 @@
   CHECK_OFFSET(InputMessage::Body::Key, eventTime, 8);
   CHECK_OFFSET(InputMessage::Body::Key, deviceId, 16);
   CHECK_OFFSET(InputMessage::Body::Key, source, 20);
-  CHECK_OFFSET(InputMessage::Body::Key, displayId, 24);
-  CHECK_OFFSET(InputMessage::Body::Key, action, 28);
-  CHECK_OFFSET(InputMessage::Body::Key, flags, 32);
-  CHECK_OFFSET(InputMessage::Body::Key, keyCode, 36);
-  CHECK_OFFSET(InputMessage::Body::Key, scanCode, 40);
-  CHECK_OFFSET(InputMessage::Body::Key, metaState, 44);
-  CHECK_OFFSET(InputMessage::Body::Key, repeatCount, 48);
-  CHECK_OFFSET(InputMessage::Body::Key, downTime, 56);
+  CHECK_OFFSET(InputMessage::Body::Key, action, 24);
+  CHECK_OFFSET(InputMessage::Body::Key, flags, 28);
+  CHECK_OFFSET(InputMessage::Body::Key, keyCode, 32);
+  CHECK_OFFSET(InputMessage::Body::Key, scanCode, 36);
+  CHECK_OFFSET(InputMessage::Body::Key, metaState, 40);
+  CHECK_OFFSET(InputMessage::Body::Key, repeatCount, 44);
+  CHECK_OFFSET(InputMessage::Body::Key, downTime, 48);
 
   CHECK_OFFSET(InputMessage::Body::Motion, seq, 0);
   CHECK_OFFSET(InputMessage::Body::Motion, eventTime, 8);
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/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index b453d19..78f8f0d 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -1108,38 +1108,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);
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index c3f4f58..4d32ea6 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -894,12 +894,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,
@@ -2354,6 +2355,7 @@
             originalMotionEntry->eventTime,
             originalMotionEntry->deviceId,
             originalMotionEntry->source,
+            originalMotionEntry->displayId,
             originalMotionEntry->policyFlags,
             action,
             originalMotionEntry->actionButton,
@@ -2364,7 +2366,6 @@
             originalMotionEntry->xPrecision,
             originalMotionEntry->yPrecision,
             originalMotionEntry->downTime,
-            originalMotionEntry->displayId,
             splitPointerCount, splitPointerProperties, splitPointerCoords, 0, 0);
 
     if (originalMotionEntry->injectionState) {
@@ -2496,10 +2497,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++) {
@@ -2543,7 +2545,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,
@@ -2559,11 +2562,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);
@@ -2612,14 +2614,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);
@@ -2687,12 +2688,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;
@@ -2700,12 +2702,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;
@@ -3996,18 +3999,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]);
@@ -4021,11 +4025,12 @@
 }
 
 void InputDispatcher::MotionEntry::appendDescription(std::string& msg) const {
-    msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, action=%d, actionButton=0x%08x, "
+    msg += StringPrintf("MotionEvent(deviceId=%d, source=0x%08x, displayId=%" PRId32
+            ", action=%d, actionButton=0x%08x, "
             "flags=0x%08x, metaState=0x%08x, buttonState=0x%08x, "
-            "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, displayId=%d, pointers=[",
-            deviceId, source, action, actionButton, flags, metaState, buttonState, edgeFlags,
-            xPrecision, yPrecision, displayId);
+            "edgeFlags=0x%08x, xPrecision=%.1f, yPrecision=%.1f, pointers=[",
+            deviceId, source, displayId, action, actionButton, flags, metaState, buttonState,
+            edgeFlags, xPrecision, yPrecision);
     for (uint32_t i = 0; i < pointerCount; i++) {
         if (i) {
             msg += ", ";
@@ -4154,8 +4159,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;
     }
@@ -4207,8 +4212,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;
     }
@@ -4220,8 +4225,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;
     }
@@ -4287,11 +4293,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;
@@ -4321,13 +4327,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));
         }
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 8da8450..5f76abe 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);
 
@@ -508,6 +508,7 @@
         nsecs_t eventTime;
         int32_t deviceId;
         uint32_t source;
+        int32_t displayId;
         int32_t action;
         int32_t actionButton;
         int32_t flags;
@@ -517,17 +518,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;
@@ -765,11 +764,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];
diff --git a/services/inputflinger/InputListener.cpp b/services/inputflinger/InputListener.cpp
index 520fea4..c36d7cf 100644
--- a/services/inputflinger/InputListener.cpp
+++ b/services/inputflinger/InputListener.cpp
@@ -67,16 +67,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 +88,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..d24be4c 100644
--- a/services/inputflinger/InputListener.h
+++ b/services/inputflinger/InputListener.h
@@ -82,6 +82,7 @@
     nsecs_t eventTime;
     int32_t deviceId;
     uint32_t source;
+    int32_t displayId;
     uint32_t policyFlags;
     int32_t action;
     int32_t actionButton;
@@ -89,7 +90,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 +106,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..50229cb 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -2279,15 +2279,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)) {
                 mOrientation = v.orientation;
-            } else {
-                mOrientation = DISPLAY_ORIENTATION_0;
             }
-        } else {
-            mOrientation = DISPLAY_ORIENTATION_0;
         }
     }
 }
@@ -2699,15 +2696,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)) {
                 mOrientation = v.orientation;
-            } else {
-                mOrientation = DISPLAY_ORIENTATION_0;
             }
-        } else {
-            mOrientation = DISPLAY_ORIENTATION_0;
         }
         bumpGeneration();
     }
@@ -2894,19 +2888,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 +2909,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 +2923,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 +2936,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);
         }
@@ -3072,10 +3066,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);
     }
@@ -5413,10 +5407,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);
     }
@@ -6336,9 +6330,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 +6343,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 +6358,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 +6368,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 +6382,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 +6393,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);
@@ -6421,9 +6415,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 +6478,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);
 }
@@ -7404,9 +7398,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/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index aa6df24..9c72c77 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;
@@ -124,7 +124,7 @@
             /*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.";
 
@@ -133,7 +133,7 @@
             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/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index ba28eb5..cba94d2 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -103,8 +103,10 @@
         "FrameTracker.cpp",
         "GpuService.cpp",
         "Layer.cpp",
+	"LayerBE.cpp",
         "LayerProtoHelper.cpp",
         "LayerRejecter.cpp",
+        "LayerStats.cpp",
         "LayerVector.cpp",
         "MessageQueue.cpp",
         "MonitoredProducer.cpp",
diff --git a/services/surfaceflinger/BufferLayer.cpp b/services/surfaceflinger/BufferLayer.cpp
index 9200207..a6caf29 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.
@@ -358,8 +373,7 @@
         return;
     }
 
-    auto releaseFenceTime =
-            std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
+    auto releaseFenceTime = std::make_shared<FenceTime>(mConsumer->getPrevFinalReleaseFence());
     mReleaseTimeline.updateSignalTimes();
     mReleaseTimeline.push(releaseFenceTime);
 
@@ -412,7 +426,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();
@@ -425,12 +439,10 @@
     // 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,
+                    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.
@@ -483,17 +495,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;
     }
@@ -520,8 +531,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;
@@ -530,15 +540,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;
     }
@@ -586,14 +595,14 @@
     auto hwcId = displayDevice->getHwcDisplayId();
     auto& hwcInfo = getBE().mHwcLayers[hwcId];
     auto& hwcLayer = hwcInfo.layer;
-    auto error = hwcLayer->setVisibleRegion(visible);
+    auto error = (*hwcLayer)->setVisibleRegion(visible);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
               to_string(error).c_str(), static_cast<int32_t>(error));
         visible.dump(LOG_TAG);
     }
 
-    error = hwcLayer->setSurfaceDamage(surfaceDamageRegion);
+    error = (*hwcLayer)->setSurfaceDamage(surfaceDamageRegion);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set surface damage: %s (%d)", mName.string(),
               to_string(error).c_str(), static_cast<int32_t>(error));
@@ -604,7 +613,7 @@
     if (getBE().compositionInfo.hwc.sidebandStream.get()) {
         setCompositionType(hwcId, HWC2::Composition::Sideband);
         ALOGV("[%s] Requesting Sideband composition", mName.string());
-        error = hwcLayer->setSidebandStream(getBE().compositionInfo.hwc.sidebandStream->handle());
+        error = (*hwcLayer)->setSidebandStream(getBE().compositionInfo.hwc.sidebandStream->handle());
         if (error != HWC2::Error::None) {
             ALOGE("[%s] Failed to set sideband stream %p: %s (%d)", mName.string(),
                   getBE().compositionInfo.hwc.sidebandStream->handle(), to_string(error).c_str(),
@@ -623,14 +632,14 @@
     }
 
     ALOGV("setPerFrameData: dataspace = %d", mDrawingState.dataSpace);
-    error = hwcLayer->setDataspace(mDrawingState.dataSpace);
+    error = (*hwcLayer)->setDataspace(mDrawingState.dataSpace);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mDrawingState.dataSpace,
               to_string(error).c_str(), static_cast<int32_t>(error));
     }
 
     const HdrMetadata& metadata = mConsumer->getCurrentHdrMetadata();
-    error = hwcLayer->setHdrMetadata(metadata);
+    error = (*hwcLayer)->setHdrMetadata(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));
@@ -638,11 +647,11 @@
 
     uint32_t hwcSlot = 0;
     sp<GraphicBuffer> hwcBuffer;
-    hwcInfo.bufferCache.getHwcBuffer(getBE().compositionInfo.mBufferSlot,
-                                     getBE().compositionInfo.mBuffer, &hwcSlot, &hwcBuffer);
+    getBE().mHwcLayers[hwcId].bufferCache.getHwcBuffer(mActiveBufferSlot, mActiveBuffer, &hwcSlot,
+                                                       &hwcBuffer);
 
     auto acquireFence = mConsumer->getCurrentFence();
-    error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
+    error = (*hwcLayer)->setBuffer(hwcSlot, hwcBuffer, acquireFence);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set buffer %p: %s (%d)", mName.string(),
               getBE().compositionInfo.mBuffer->handle, to_string(error).c_str(),
@@ -653,7 +662,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;
     }
 
@@ -668,8 +677,7 @@
     sp<IGraphicBufferConsumer> consumer;
     BufferQueue::createBufferQueue(&producer, &consumer, true);
     mProducer = new MonitoredProducer(producer, mFlinger, this);
-    mConsumer = new BufferLayerConsumer(consumer,
-            mFlinger->getRenderEngine(), mTextureName, this);
+    mConsumer = new BufferLayerConsumer(consumer, mFlinger->getRenderEngine(), mTextureName, this);
     mConsumer->setConsumerUsageBits(getEffectiveUsage(0));
     mConsumer->setContentsChangedListener(this);
     mConsumer->setName(mName);
@@ -701,8 +709,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());
             }
@@ -725,8 +732,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());
             }
@@ -824,21 +830,17 @@
     texCoords[2] = vec2(right, 1.0f - bottom);
     texCoords[3] = vec2(right, 1.0f - top);
 
-    auto& engine(mFlinger->getRenderEngine());
-    engine.setupLayerBlending(mPremultipliedAlpha, isOpaque(s), false /* disableTexture */,
-                              getColor());
-    engine.setSourceDataSpace(mCurrentState.dataSpace);
+    getBE().compositionInfo.re.preMultipliedAlpha = mPremultipliedAlpha;
+    getBE().compositionInfo.re.opaque = isOpaque(s);
+    getBE().compositionInfo.re.disableTexture = false;
+    getBE().compositionInfo.re.color = getColor();
+    getBE().compositionInfo.hwc.dataspace = mCurrentState.dataSpace;
 
     if (mCurrentState.dataSpace == HAL_DATASPACE_BT2020_ITU_PQ &&
         mConsumer->getCurrentApi() == NATIVE_WINDOW_API_MEDIA &&
         getBE().compositionInfo.mBuffer->getPixelFormat() == HAL_PIXEL_FORMAT_RGBA_1010102) {
-        engine.setSourceY410BT2020(true);
+        getBE().compositionInfo.re.Y410BT2020 = true;
     }
-
-    engine.drawMesh(getBE().mMesh);
-    engine.disableBlending();
-
-    engine.setSourceY410BT2020(false);
 }
 
 uint32_t BufferLayer::getProducerStickyTransform() const {
@@ -891,8 +893,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 6b02f8c..c7b09ad 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;
 
diff --git a/services/surfaceflinger/ColorLayer.cpp b/services/surfaceflinger/ColorLayer.cpp
index 80a90a7..71975c8 100644
--- a/services/surfaceflinger/ColorLayer.cpp
+++ b/services/surfaceflinger/ColorLayer.cpp
@@ -46,16 +46,27 @@
                         bool useIdentityTransform) const {
     const State& s(getDrawingState());
     if (s.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 */, s.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 = s.color;
     }
 }
 
+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();
+}
+
 bool ColorLayer::isVisible() const {
     const Layer::State& s(getDrawingState());
     return !isHiddenByPolicy() && s.color.a;
@@ -68,7 +79,7 @@
     auto hwcId = displayDevice->getHwcDisplayId();
     auto& hwcInfo = getBE().mHwcLayers[hwcId];
     auto& hwcLayer = hwcInfo.layer;
-    auto error = hwcLayer->setVisibleRegion(visible);
+    auto error = (*hwcLayer)->setVisibleRegion(visible);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set visible region: %s (%d)", mName.string(),
               to_string(error).c_str(), static_cast<int32_t>(error));
@@ -77,14 +88,14 @@
 
     setCompositionType(hwcId, HWC2::Composition::SolidColor);
 
-    error = hwcLayer->setDataspace(mDrawingState.dataSpace);
+    error = (*hwcLayer)->setDataspace(mDrawingState.dataSpace);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set dataspace %d: %s (%d)", mName.string(), mDrawingState.dataSpace,
               to_string(error).c_str(), static_cast<int32_t>(error));
     }
 
     half4 color = getColor();
-    error = hwcLayer->setColor({static_cast<uint8_t>(std::round(255.0f * color.r)),
+    error = (*hwcLayer)->setColor({static_cast<uint8_t>(std::round(255.0f * color.r)),
                                 static_cast<uint8_t>(std::round(255.0f * color.g)),
                                 static_cast<uint8_t>(std::round(255.0f * color.b)), 255});
     if (error != HWC2::Error::None) {
@@ -93,7 +104,7 @@
     }
 
     // Clear out the transform, because it doesn't make sense absent a source buffer
-    error = hwcLayer->setTransform(HWC2::Transform::None);
+    error = (*hwcLayer)->setTransform(HWC2::Transform::None);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(), to_string(error).c_str(),
               static_cast<int32_t>(error));
diff --git a/services/surfaceflinger/ColorLayer.h b/services/surfaceflinger/ColorLayer.h
index 0cde398..e8fb92d 100644
--- a/services/surfaceflinger/ColorLayer.h
+++ b/services/surfaceflinger/ColorLayer.h
@@ -32,6 +32,7 @@
     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;
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 543f60a..50c0191 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -32,6 +32,7 @@
     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;
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/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 2499a98..3dc8cae 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -61,11 +61,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,
@@ -96,7 +91,8 @@
         mQueueItems(),
         mLastFrameNumberReceived(0),
         mAutoRefresh(false),
-        mFreezeGeometryUpdates(false) {
+        mFreezeGeometryUpdates(false),
+        mBE{this, name.string()} {
 
     mCurrentCrop.makeInvalid();
 
@@ -221,15 +217,14 @@
 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);
+
+    std::shared_ptr<LayerContainer> layer(new LayerContainer(hwc, hwcId));
     if (!layer) {
         return false;
     }
     LayerBE::HWCInfo& hwcInfo = getBE().mHwcLayers[hwcId];
     hwcInfo.hwc = hwc;
     hwcInfo.layer = layer;
-    layer->setLayerDestroyedListener(
-            [this, hwcId](HWC2::Layer* /*layer*/) { getBE().mHwcLayers.erase(hwcId); });
     return true;
 }
 
@@ -240,11 +235,12 @@
     auto& hwcInfo = getBE().mHwcLayers[hwcId];
     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);
-    // The layer destroyed listener should have cleared the entry from
-    // mHwcLayers. Verify that.
-    LOG_ALWAYS_FATAL_IF(getBE().mHwcLayers.count(hwcId) != 0,
-                        "Stale layer entry in getBE().mHwcLayers");
+    hwcInfo.layer = nullptr;
+
+    if (getBE().mHwcLayers.count(hwcId) == 1) {
+        getBE().mHwcLayers.erase(hwcId);
+    }
+
     return true;
 }
 
@@ -503,7 +499,7 @@
         blendMode =
                 mPremultipliedAlpha ? HWC2::BlendMode::Premultiplied : HWC2::BlendMode::Coverage;
     }
-    auto error = hwcLayer->setBlendMode(blendMode);
+    auto error = (*hwcLayer)->setBlendMode(blendMode);
     ALOGE_IF(error != HWC2::Error::None,
              "[%s] Failed to set blend mode %s:"
              " %s (%d)",
@@ -551,7 +547,7 @@
     }
     const Transform& tr(displayDevice->getTransform());
     Rect transformedFrame = tr.transform(frame);
-    error = hwcLayer->setDisplayFrame(transformedFrame);
+    error = (*hwcLayer)->setDisplayFrame(transformedFrame);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set display frame [%d, %d, %d, %d]: %s (%d)", mName.string(),
               transformedFrame.left, transformedFrame.top, transformedFrame.right,
@@ -561,7 +557,7 @@
     }
 
     FloatRect sourceCrop = computeCrop(displayDevice);
-    error = hwcLayer->setSourceCrop(sourceCrop);
+    error = (*hwcLayer)->setSourceCrop(sourceCrop);
     if (error != HWC2::Error::None) {
         ALOGE("[%s] Failed to set source crop [%.3f, %.3f, %.3f, %.3f]: "
               "%s (%d)",
@@ -572,13 +568,13 @@
     }
 
     float alpha = static_cast<float>(getAlpha());
-    error = hwcLayer->setPlaneAlpha(alpha);
+    error = (*hwcLayer)->setPlaneAlpha(alpha);
     ALOGE_IF(error != HWC2::Error::None,
              "[%s] Failed to set plane alpha %.3f: "
              "%s (%d)",
              mName.string(), alpha, to_string(error).c_str(), static_cast<int32_t>(error));
 
-    error = hwcLayer->setZOrder(z);
+    error = (*hwcLayer)->setZOrder(z);
     ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set Z %u: %s (%d)", mName.string(), z,
              to_string(error).c_str(), static_cast<int32_t>(error));
 
@@ -593,7 +589,7 @@
         }
     }
 
-    error = hwcLayer->setInfo(type, appId);
+    error = (*hwcLayer)->setInfo(type, appId);
     ALOGE_IF(error != HWC2::Error::None, "[%s] Failed to set info (%d)", mName.string(),
              static_cast<int32_t>(error));
 
@@ -641,7 +637,8 @@
         hwcInfo.forceClientComposition = true;
     } else {
         auto transform = static_cast<HWC2::Transform>(orientation);
-        auto error = hwcLayer->setTransform(transform);
+        hwcInfo.transform = transform;
+        auto error = (*hwcLayer)->setTransform(transform);
         ALOGE_IF(error != HWC2::Error::None,
                  "[%s] Failed to set transform %s: "
                  "%s (%d)",
@@ -694,7 +691,7 @@
     auto& displayTransform(displayDevice->getTransform());
     auto position = displayTransform.transform(frame);
 
-    auto error = getBE().mHwcLayers[hwcId].layer->setCursorPosition(position.left,
+    auto error = (*getBE().mHwcLayers[hwcId].layer)->setCursorPosition(position.left,
                                                                               position.top);
     ALOGE_IF(error != HWC2::Error::None,
              "[%s] Failed to set cursor position "
@@ -738,13 +735,13 @@
     }
     auto& hwcInfo = getBE().mHwcLayers[hwcId];
     auto& hwcLayer = hwcInfo.layer;
-    ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", hwcLayer->getId(), to_string(type).c_str(),
+    ALOGV("setCompositionType(%" PRIx64 ", %s, %d)", (*hwcLayer)->getId(), to_string(type).c_str(),
           static_cast<int>(callIntoHwc));
     if (hwcInfo.compositionType != type) {
         ALOGV("    actually setting");
         hwcInfo.compositionType = type;
         if (callIntoHwc) {
-            auto error = hwcLayer->setCompositionType(type);
+            auto error = (*hwcLayer)->setCompositionType(type);
             ALOGE_IF(error != HWC2::Error::None,
                      "[%s] Failed to set "
                      "composition type %s: %s (%d)",
@@ -1442,7 +1439,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();
@@ -1925,6 +1922,21 @@
     layerInfo->set_app_id(state.appId);
 }
 
+void Layer::writeToProto(LayerProto* layerInfo, int32_t hwcId) {
+    writeToProto(layerInfo, LayerVector::StateSet::Drawing);
+
+    const auto& hwcInfo = getBE().mHwcLayers.at(hwcId);
+
+    const Rect& frame = hwcInfo.displayFrame;
+    LayerProtoHelper::writeToProto(frame, layerInfo->mutable_hwc_frame());
+
+    const FloatRect& crop = hwcInfo.sourceCrop;
+    LayerProtoHelper::writeToProto(crop, layerInfo->mutable_hwc_crop());
+
+    const int32_t transform = static_cast<int32_t>(hwcInfo.transform);
+    layerInfo->set_hwc_transform(transform);
+}
+
 // ---------------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 9a9b5e6..5c00833 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -42,6 +42,7 @@
 #include "MonitoredProducer.h"
 #include "SurfaceFlinger.h"
 #include "Transform.h"
+#include "LayerBE.h"
 
 #include <layerproto/LayerProtoHeader.h>
 #include "DisplayHardware/HWComposer.h"
@@ -72,68 +73,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) {}
-
-        HWComposer* hwc;
-        HWC2::Layer* layer;
-        bool forceClientComposition;
-        HWC2::Composition compositionType;
-        bool clearClientTarget;
-        Rect displayFrame;
-        FloatRect sourceCrop;
-        HWComposerBufferCache bufferCache;
-    };
-
-    // 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;
 
@@ -357,6 +296,8 @@
     void writeToProto(LayerProto* layerInfo,
                       LayerVector::StateSet stateSet = LayerVector::StateSet::Drawing);
 
+    void writeToProto(LayerProto* layerInfo, int32_t hwcId);
+
 protected:
     /*
      * onDraw - draws the surface.
@@ -419,6 +360,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.
      */
@@ -506,7 +457,15 @@
         if (getBE().mHwcLayers.count(hwcId) == 0) {
             return nullptr;
         }
-        return getBE().mHwcLayers[hwcId].layer;
+        return *(getBE().mHwcLayers[hwcId].layer.get());
+    }
+
+    bool setHwcLayer(int32_t hwcId) {
+        if (getBE().mHwcLayers.count(hwcId) == 0) {
+            return false;
+        }
+        getBE().compositionInfo.hwc.hwcLayer = getBE().mHwcLayers[hwcId].layer;
+        return true;
     }
 
     // -----------------------------------------------------------------------
diff --git a/services/surfaceflinger/LayerBE.cpp b/services/surfaceflinger/LayerBE.cpp
new file mode 100644
index 0000000..78330fd
--- /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, static_cast<HWC2::Layer*>(*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..854cdd6
--- /dev/null
+++ b/services/surfaceflinger/LayerBE.h
@@ -0,0 +1,151 @@
+/*
+ * 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;
+
+class LayerContainer
+{
+    public:
+        LayerContainer(HWComposer* hwc, int32_t hwcId) : mHwc(hwc), mHwcId(hwcId) {
+            mLayer = hwc->createLayer(hwcId);
+        }
+
+        ~LayerContainer() {
+            mHwc->destroyLayer(mHwcId, mLayer);
+        }
+
+        HWC2::Layer* operator->() {
+            return mLayer;
+        }
+
+        operator HWC2::Layer*const () const {
+            return mLayer;
+        }
+
+    private:
+        HWComposer* mHwc;
+        int32_t mHwcId;
+        HWC2::Layer* mLayer;
+};
+
+struct CompositionInfo {
+    std::string layerName;
+    HWC2::Composition compositionType;
+    sp<GraphicBuffer> mBuffer = nullptr;
+    int mBufferSlot = BufferQueue::INVALID_BUFFER_SLOT;
+    LayerBE* layer = nullptr;
+    struct {
+        std::shared_ptr<LayerContainer> hwcLayer;
+        int32_t hwid = -1;
+        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;
+        android_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;
+        std::shared_ptr<LayerContainer> 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/LayerProtoHelper.cpp b/services/surfaceflinger/LayerProtoHelper.cpp
index 6a33148..cc39550 100644
--- a/services/surfaceflinger/LayerProtoHelper.cpp
+++ b/services/surfaceflinger/LayerProtoHelper.cpp
@@ -37,6 +37,13 @@
     rectProto->set_right(rect.right);
 }
 
+void LayerProtoHelper::writeToProto(const FloatRect& rect, FloatRectProto* rectProto) {
+    rectProto->set_left(rect.left);
+    rectProto->set_top(rect.top);
+    rectProto->set_bottom(rect.bottom);
+    rectProto->set_right(rect.right);
+}
+
 void LayerProtoHelper::writeToProto(const half4 color, ColorProto* colorProto) {
     colorProto->set_r(color.r);
     colorProto->set_g(color.g);
diff --git a/services/surfaceflinger/LayerProtoHelper.h b/services/surfaceflinger/LayerProtoHelper.h
index 45a0b5d..860da63 100644
--- a/services/surfaceflinger/LayerProtoHelper.h
+++ b/services/surfaceflinger/LayerProtoHelper.h
@@ -29,6 +29,7 @@
 class LayerProtoHelper {
 public:
     static void writeToProto(const Rect& rect, RectProto* rectProto);
+    static void writeToProto(const FloatRect& rect, FloatRectProto* rectProto);
     static void writeToProto(const Region& region, RegionProto* regionProto);
     static void writeToProto(const half4 color, ColorProto* colorProto);
     static void writeToProto(const Transform& transform, TransformProto* transformProto);
@@ -36,4 +37,4 @@
 };
 
 } // namespace surfaceflinger
-} // namespace android
\ No newline at end of file
+} // namespace android
diff --git a/services/surfaceflinger/LayerStats.cpp b/services/surfaceflinger/LayerStats.cpp
new file mode 100644
index 0000000..ad1043f
--- /dev/null
+++ b/services/surfaceflinger/LayerStats.cpp
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#undef LOG_TAG
+#define LOG_TAG "LayerStats"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "LayerStats.h"
+#include "DisplayHardware/HWComposer.h"
+
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <utils/String8.h>
+#include <utils/Trace.h>
+
+namespace android {
+
+void LayerStats::enable() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (mEnabled) return;
+    mLayerStatsMap.clear();
+    mEnabled = true;
+    ALOGD("Logging enabled");
+}
+
+void LayerStats::disable() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    if (!mEnabled) return;
+    mEnabled = false;
+    ALOGD("Logging disabled");
+}
+
+void LayerStats::clear() {
+    ATRACE_CALL();
+    std::lock_guard<std::mutex> lock(mMutex);
+    mLayerStatsMap.clear();
+    ALOGD("Cleared current layer stats");
+}
+
+bool LayerStats::isEnabled() {
+    return mEnabled;
+}
+
+void LayerStats::traverseLayerTreeStatsLocked(
+        std::vector<std::unique_ptr<LayerProtoParser::Layer>> layerTree,
+        const LayerProtoParser::LayerGlobal* layerGlobal) {
+    for (std::unique_ptr<LayerProtoParser::Layer>& layer : layerTree) {
+        if (!layer) continue;
+        traverseLayerTreeStatsLocked(std::move(layer->children), layerGlobal);
+        std::string key =
+                base::StringPrintf("%s,%s,%s,%s,%s,%s,%s,%s,%s",
+                                   destinationLocation(layer->hwcFrame.left,
+                                                       layerGlobal->resolution[0], true),
+                                   destinationLocation(layer->hwcFrame.top,
+                                                       layerGlobal->resolution[1], false),
+                                   destinationSize(layer->hwcFrame.right - layer->hwcFrame.left,
+                                                   layerGlobal->resolution[0], true),
+                                   destinationSize(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                                                   layerGlobal->resolution[1], false),
+                                   layer->type.c_str(), scaleRatioWH(layer.get()).c_str(),
+                                   layerTransform(layer->hwcTransform), layer->pixelFormat.c_str(),
+                                   layer->dataspace.c_str());
+        mLayerStatsMap[key]++;
+    }
+}
+
+void LayerStats::logLayerStats(const LayersProto& layersProto) {
+    ATRACE_CALL();
+    auto layerGlobal = LayerProtoParser::generateLayerGlobalInfo(layersProto);
+    auto layerTree = LayerProtoParser::generateLayerTree(layersProto);
+    std::lock_guard<std::mutex> lock(mMutex);
+    traverseLayerTreeStatsLocked(std::move(layerTree), &layerGlobal);
+}
+
+void LayerStats::dump(String8& result) {
+    ATRACE_CALL();
+    ALOGD("Dumping");
+    result.append("Count,DstPosX,DstPosY,DstWidth,DstHeight,LayerType,WScale,HScale,");
+    result.append("Transform,PixelFormat,Dataspace\n");
+    std::lock_guard<std::mutex> lock(mMutex);
+    for (auto& u : mLayerStatsMap) {
+        result.appendFormat("%u,%s\n", u.second, u.first.c_str());
+    }
+}
+
+const char* LayerStats::destinationLocation(int32_t location, int32_t range, bool isHorizontal) {
+    static const char* locationArray[8] = {"0", "1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8"};
+    int32_t ratio = location * 8 / range;
+    if (ratio < 0) return "N/A";
+    if (isHorizontal) {
+        // X location is divided into 4 buckets {"0", "1/4", "1/2", "3/4"}
+        if (ratio > 6) return "3/4";
+        // use index 0, 2, 4, 6
+        return locationArray[ratio & ~1];
+    }
+    if (ratio > 7) return "7/8";
+    return locationArray[ratio];
+}
+
+const char* LayerStats::destinationSize(int32_t size, int32_t range, bool isWidth) {
+    static const char* sizeArray[8] = {"1/8", "1/4", "3/8", "1/2", "5/8", "3/4", "7/8", "1"};
+    int32_t ratio = size * 8 / range;
+    if (ratio < 0) return "N/A";
+    if (isWidth) {
+        // width is divided into 4 buckets {"1/4", "1/2", "3/4", "1"}
+        if (ratio > 6) return "1";
+        // use index 1, 3, 5, 7
+        return sizeArray[ratio | 1];
+    }
+    if (ratio > 7) return "1";
+    return sizeArray[ratio];
+}
+
+const char* LayerStats::layerTransform(int32_t transform) {
+    return getTransformName(static_cast<hwc_transform_t>(transform));
+}
+
+std::string LayerStats::scaleRatioWH(const LayerProtoParser::Layer* layer) {
+    if (!layer->type.compare("ColorLayer")) return "N/A,N/A";
+    std::string ret = "";
+    if (isRotated(layer->hwcTransform)) {
+        ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
+                          static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
+        ret += ",";
+        ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                          static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
+    } else {
+        ret += scaleRatio(layer->hwcFrame.right - layer->hwcFrame.left,
+                          static_cast<int32_t>(layer->hwcCrop.right - layer->hwcCrop.left));
+        ret += ",";
+        ret += scaleRatio(layer->hwcFrame.bottom - layer->hwcFrame.top,
+                          static_cast<int32_t>(layer->hwcCrop.bottom - layer->hwcCrop.top));
+    }
+    return ret;
+}
+
+const char* LayerStats::scaleRatio(int32_t destinationScale, int32_t sourceScale) {
+    // Make scale buckets from <1/64 to >= 16, to avoid floating point
+    // calculation, x64 on destinationScale first
+    int32_t scale = destinationScale * 64 / sourceScale;
+    if (!scale) return "<1/64";
+    if (scale < 2) return "1/64";
+    if (scale < 4) return "1/32";
+    if (scale < 8) return "1/16";
+    if (scale < 16) return "1/8";
+    if (scale < 32) return "1/4";
+    if (scale < 64) return "1/2";
+    if (scale < 128) return "1";
+    if (scale < 256) return "2";
+    if (scale < 512) return "4";
+    if (scale < 1024) return "8";
+    return ">=16";
+}
+
+bool LayerStats::isRotated(int32_t transform) {
+    return transform & HWC_TRANSFORM_ROT_90;
+}
+
+bool LayerStats::isVFlipped(int32_t transform) {
+    return transform & HWC_TRANSFORM_FLIP_V;
+}
+
+bool LayerStats::isHFlipped(int32_t transform) {
+    return transform & HWC_TRANSFORM_FLIP_H;
+}
+
+}  // namespace android
diff --git a/services/surfaceflinger/LayerStats.h b/services/surfaceflinger/LayerStats.h
new file mode 100644
index 0000000..9522725
--- /dev/null
+++ b/services/surfaceflinger/LayerStats.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <layerproto/LayerProtoHeader.h>
+#include <layerproto/LayerProtoParser.h>
+#include <mutex>
+#include <unordered_map>
+
+using namespace android::surfaceflinger;
+
+namespace android {
+class String8;
+
+class LayerStats {
+public:
+    void enable();
+    void disable();
+    void clear();
+    bool isEnabled();
+    void logLayerStats(const LayersProto& layersProto);
+    void dump(String8& result);
+
+private:
+    // Traverse layer tree to get all visible layers' stats
+    void traverseLayerTreeStatsLocked(
+        std::vector<std::unique_ptr<LayerProtoParser::Layer>> layerTree,
+        const LayerProtoParser::LayerGlobal* layerGlobal);
+    // Convert layer's top-left position into 8x8 percentage of the display
+    static const char* destinationLocation(int32_t location, int32_t range, bool isHorizontal);
+    // Convert layer's size into 8x8 percentage of the display
+    static const char* destinationSize(int32_t size, int32_t range, bool isWidth);
+    // Return the name of the transform
+    static const char* layerTransform(int32_t transform);
+    // Calculate scale ratios of layer's width/height with rotation information
+    static std::string scaleRatioWH(const LayerProtoParser::Layer* layer);
+    // Calculate scale ratio from source to destination and convert to string
+    static const char* scaleRatio(int32_t destinationScale, int32_t sourceScale);
+    // Return whether the original buffer is rotated in final composition
+    static bool isRotated(int32_t transform);
+    // Return whether the original buffer is V-flipped in final composition
+    static bool isVFlipped(int32_t transform);
+    // Return whether the original buffer is H-flipped in final composition
+    static bool isHFlipped(int32_t transform);
+
+    bool mEnabled = false;
+    // Protect mLayersStatsMap
+    std::mutex mMutex;
+    // Hashmap for tracking the layer stats
+    // KEY is a concatenation of a particular set of layer properties
+    // VALUE is the number of times this particular get scanned out
+    std::unordered_map<std::string, uint32_t> mLayerStatsMap;
+};
+
+}  // namespace android
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 2f653ef..b7931bc 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1483,6 +1483,7 @@
     setUpHWComposer();
     doDebugFlashRegions();
     doTracing("handleRefresh");
+    logLayerStats();
     doComposition();
     postComposition(refreshStartTime);
 
@@ -1552,6 +1553,25 @@
     }
 }
 
+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;
+            }
+        }
+        if (hwcId < 0) {
+            ALOGE("LayerStats: Hmmm, no primary display?");
+            return;
+        }
+        mLayerStats.logLayerStats(dumpVisibleLayersProtoInfo(hwcId));
+    }
+}
+
 void SurfaceFlinger::preComposition(nsecs_t refreshStartTime)
 {
     ATRACE_CALL();
@@ -2047,7 +2067,7 @@
                         displayDevice->getClientTargetAcquireFence());
             }
 
-            layer->onLayerDisplayed(releaseFence);
+            layer->getBE().onLayerDisplayed(releaseFence);
         }
 
         // We've got a list of layers needing fences, that are disjoint with
@@ -2056,7 +2076,7 @@
         if (!displayDevice->getLayersNeedingFences().isEmpty()) {
             sp<Fence> presentFence = getBE().mHwc->getPresentFence(hwcId);
             for (auto& layer : displayDevice->getLayersNeedingFences()) {
-                layer->onLayerDisplayed(presentFence);
+                layer->getBE().onLayerDisplayed(presentFence);
             }
         }
 
@@ -3770,6 +3790,34 @@
                 dumpWideColorInfo(result);
                 dumpAll = false;
             }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--enable-layer-stats"))) {
+                index++;
+                mLayerStats.enable();
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--disable-layer-stats"))) {
+                index++;
+                mLayerStats.disable();
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--clear-layer-stats"))) {
+                index++;
+                mLayerStats.clear();
+                dumpAll = false;
+            }
+
+            if ((index < numArgs) &&
+                (args[index] == String16("--dump-layer-stats"))) {
+                index++;
+                mLayerStats.dump(result);
+                dumpAll = false;
+            }
         }
 
         if (dumpAll) {
@@ -3977,6 +4025,25 @@
     return layersProto;
 }
 
+LayersProto SurfaceFlinger::dumpVisibleLayersProtoInfo(int32_t hwcId) const {
+    LayersProto layersProto;
+
+    const sp<DisplayDevice>& displayDevice(mDisplays[hwcId]);
+    SizeProto* resolution = layersProto.mutable_resolution();
+    resolution->set_w(displayDevice->getWidth());
+    resolution->set_h(displayDevice->getHeight());
+
+    mDrawingState.traverseInZOrder([&](Layer* layer) {
+        if (!layer->visibleRegion.isEmpty() &&
+            layer->getBE().mHwcLayers.count(hwcId)) {
+            LayerProto* layerProto = layersProto.add_layers();
+            layer->writeToProto(layerProto, hwcId);
+        }
+    });
+
+    return layersProto;
+}
+
 void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
         String8& result) const
 {
@@ -4746,7 +4813,7 @@
 
     traverseLayers([&](Layer* layer) {
         if (filtering) layer->setFiltering(true);
-        layer->draw(renderArea, useIdentityTransform);
+        layer->drawNow(renderArea, useIdentityTransform);
         if (filtering) layer->setFiltering(false);
     });
 }
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 42d8112..99bbb13 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -44,6 +44,7 @@
 #include <gui/LayerState.h>
 
 #include <gui/OccupancyTracker.h>
+#include <gui/BufferQueue.h>
 
 #include <hardware/hwcomposer_defs.h>
 
@@ -55,11 +56,13 @@
 #include "DisplayDevice.h"
 #include "DispSync.h"
 #include "FrameTracker.h"
+#include "LayerStats.h"
 #include "LayerVector.h"
 #include "MessageQueue.h"
 #include "SurfaceInterceptor.h"
 #include "SurfaceTracing.h"
 #include "StartPropertySetThread.h"
+#include "LayerBE.h"
 
 #include "DisplayHardware/HWC2.h"
 #include "DisplayHardware/HWComposer.h"
@@ -645,6 +648,7 @@
     void doComposition();
     void doDebugFlashRegions();
     void doTracing(const char* where);
+    void logLayerStats();
     void doDisplayComposition(const sp<const DisplayDevice>& displayDevice, const Region& dirtyRegion);
 
     // compose surfaces for display hw. this fails if using GL and the surface
@@ -711,6 +715,7 @@
     void dumpBufferingStats(String8& result) const;
     void dumpWideColorInfo(String8& result) const;
     LayersProto dumpProtoInfo(LayerVector::StateSet stateSet) const;
+    LayersProto dumpVisibleLayersProtoInfo(int32_t hwcId) const;
 
     bool isLayerTripleBufferingDisabled() const {
         return this->mLayerTripleBufferingDisabled;
@@ -797,6 +802,7 @@
     std::unique_ptr<SurfaceInterceptor> mInterceptor =
             std::make_unique<impl::SurfaceInterceptor>(this);
     SurfaceTracing mTracing;
+    LayerStats mLayerStats;
     bool mUseHwcVirtualDisplays = false;
 
     // Restrict layers to use two buffers in their bufferqueues.
diff --git a/services/surfaceflinger/layerproto/LayerProtoParser.cpp b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
index 47e5d1f..b10e07b 100644
--- a/services/surfaceflinger/layerproto/LayerProtoParser.cpp
+++ b/services/surfaceflinger/layerproto/LayerProtoParser.cpp
@@ -42,6 +42,11 @@
     return sortLayers(lhs.get(), rhs.get());
 }
 
+const LayerProtoParser::LayerGlobal LayerProtoParser::generateLayerGlobalInfo(
+        const LayersProto& layersProto) {
+    return {{layersProto.resolution().w(), layersProto.resolution().h()}};
+}
+
 std::vector<std::unique_ptr<LayerProtoParser::Layer>> LayerProtoParser::generateLayerTree(
         const LayersProto& layersProto) {
     std::unordered_map<int32_t, LayerProtoParser::Layer*> layerMap = generateMap(layersProto);
@@ -106,6 +111,9 @@
     layer->activeBuffer = generateActiveBuffer(layerProto.active_buffer());
     layer->queuedFrames = layerProto.queued_frames();
     layer->refreshPending = layerProto.refresh_pending();
+    layer->hwcFrame = generateRect(layerProto.hwc_frame());
+    layer->hwcCrop = generateFloatRect(layerProto.hwc_crop());
+    layer->hwcTransform = layerProto.hwc_transform();
     layer->windowType = layerProto.window_type();
     layer->appId = layerProto.app_id();
 
@@ -133,6 +141,16 @@
     return rect;
 }
 
+LayerProtoParser::FloatRect LayerProtoParser::generateFloatRect(const FloatRectProto& rectProto) {
+    LayerProtoParser::FloatRect rect;
+    rect.left = rectProto.left();
+    rect.top = rectProto.top();
+    rect.right = rectProto.right();
+    rect.bottom = rectProto.bottom();
+
+    return rect;
+}
+
 LayerProtoParser::Transform LayerProtoParser::generateTransform(
         const TransformProto& transformProto) {
     LayerProtoParser::Transform transform;
@@ -246,6 +264,10 @@
     return StringPrintf("[%3d, %3d, %3d, %3d]", left, top, right, bottom);
 }
 
+std::string LayerProtoParser::FloatRect::to_string() const {
+    return StringPrintf("[%.2f, %.2f, %.2f, %.2f]", left, top, right, bottom);
+}
+
 std::string LayerProtoParser::Region::to_string(const char* what) const {
     std::string result =
             StringPrintf("  Region %s (this=%lx count=%d)\n", what, static_cast<unsigned long>(id),
diff --git a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
index b56a6fb..fd893da 100644
--- a/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
+++ b/services/surfaceflinger/layerproto/include/layerproto/LayerProtoParser.h
@@ -13,6 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+#pragma once
 
 #include <layerproto/LayerProtoHeader.h>
 
@@ -57,6 +58,16 @@
         std::string to_string() const;
     };
 
+    class FloatRect {
+    public:
+        float left;
+        float top;
+        float right;
+        float bottom;
+
+        std::string to_string() const;
+    };
+
     class Region {
     public:
         uint64_t id;
@@ -96,12 +107,21 @@
         LayerProtoParser::ActiveBuffer activeBuffer;
         int32_t queuedFrames;
         bool refreshPending;
+        LayerProtoParser::Rect hwcFrame;
+        LayerProtoParser::FloatRect hwcCrop;
+        int32_t hwcTransform;
         int32_t windowType;
         int32_t appId;
 
         std::string to_string() const;
     };
 
+    class LayerGlobal {
+    public:
+        int2 resolution;
+    };
+
+    static const LayerGlobal generateLayerGlobalInfo(const LayersProto& layersProto);
     static std::vector<std::unique_ptr<Layer>> generateLayerTree(const LayersProto& layersProto);
     static std::string layersToString(std::vector<std::unique_ptr<LayerProtoParser::Layer>> layers);
 
@@ -110,6 +130,7 @@
     static LayerProtoParser::Layer* generateLayer(const LayerProto& layerProto);
     static LayerProtoParser::Region generateRegion(const RegionProto& regionProto);
     static LayerProtoParser::Rect generateRect(const RectProto& rectProto);
+    static LayerProtoParser::FloatRect generateFloatRect(const FloatRectProto& rectProto);
     static LayerProtoParser::Transform generateTransform(const TransformProto& transformProto);
     static LayerProtoParser::ActiveBuffer generateActiveBuffer(
             const ActiveBufferProto& activeBufferProto);
diff --git a/services/surfaceflinger/layerproto/layers.proto b/services/surfaceflinger/layerproto/layers.proto
index f18386b..6675aae 100644
--- a/services/surfaceflinger/layerproto/layers.proto
+++ b/services/surfaceflinger/layerproto/layers.proto
@@ -7,6 +7,7 @@
 // Contains a list of all layers.
 message LayersProto {
   repeated LayerProto layers = 1;
+  optional SizeProto resolution = 2;
 }
 
 // Information about each layer.
@@ -64,8 +65,14 @@
   // The number of frames available.
   optional int32 queued_frames = 28;
   optional bool refresh_pending = 29;
-  optional int32 window_type = 30;
-  optional int32 app_id = 31;
+  // The layer's composer backend destination frame
+  optional RectProto hwc_frame = 30;
+  // The layer's composer backend source crop
+  optional FloatRectProto hwc_crop = 31;
+  // The layer's composer backend transform
+  optional int32 hwc_transform = 32;
+  optional int32 window_type = 33;
+  optional int32 app_id = 34;
 }
 
 message PositionProto {
@@ -97,6 +104,13 @@
   optional int32 bottom = 4;
 }
 
+message FloatRectProto {
+  optional float left = 1;
+  optional float top = 2;
+  optional float right = 3;
+  optional float bottom = 4;
+}
+
 message ActiveBufferProto {
   optional uint32 width = 1;
   optional uint32 height = 2;
@@ -109,4 +123,4 @@
   optional float g = 2;
   optional float b = 3;
   optional float a = 4;
-}
\ No newline at end of file
+}
diff --git a/vulkan/libvulkan/code-generator.tmpl b/vulkan/libvulkan/code-generator.tmpl
index 84644a9..1f4df1e 100644
--- a/vulkan/libvulkan/code-generator.tmpl
+++ b/vulkan/libvulkan/code-generator.tmpl
@@ -983,6 +983,7 @@
     {{else if eq $.Name "vkDestroyImage"}}true
 
     {{else if eq $.Name "vkGetPhysicalDeviceProperties"}}true
+    {{else if eq $.Name "vkGetPhysicalDeviceProperties2"}}true
     {{else if eq $.Name "vkGetPhysicalDeviceProperties2KHR"}}true
     {{end}}
 
diff --git a/vulkan/libvulkan/driver.cpp b/vulkan/libvulkan/driver.cpp
index dec39e0..8b8b280 100644
--- a/vulkan/libvulkan/driver.cpp
+++ b/vulkan/libvulkan/driver.cpp
@@ -801,7 +801,8 @@
     const InstanceData& data = GetData(physicalDevice);
 
     // GPDP2 must be present and enabled on the instance.
-    if (!data.driver.GetPhysicalDeviceProperties2KHR)
+    if (!data.driver.GetPhysicalDeviceProperties2KHR &&
+        !data.driver.GetPhysicalDeviceProperties2)
         return false;
 
     // Request the android-specific presentation properties via GPDP2
@@ -819,8 +820,12 @@
     presentation_properties->pNext = nullptr;
     presentation_properties->sharedImage = VK_FALSE;
 
-    data.driver.GetPhysicalDeviceProperties2KHR(physicalDevice,
-                                                &properties);
+    if (data.driver.GetPhysicalDeviceProperties2KHR) {
+        data.driver.GetPhysicalDeviceProperties2KHR(physicalDevice,
+                                                    &properties);
+    } else {
+        data.driver.GetPhysicalDeviceProperties2(physicalDevice, &properties);
+    }
 
     return true;
 }
diff --git a/vulkan/libvulkan/driver_gen.cpp b/vulkan/libvulkan/driver_gen.cpp
index 51e3abf..ec98b9f 100644
--- a/vulkan/libvulkan/driver_gen.cpp
+++ b/vulkan/libvulkan/driver_gen.cpp
@@ -494,6 +494,7 @@
     INIT_PROC(true, instance, CreateDevice);
     INIT_PROC(true, instance, EnumerateDeviceExtensionProperties);
     INIT_PROC(false, instance, EnumeratePhysicalDeviceGroups);
+    INIT_PROC(false, instance, GetPhysicalDeviceProperties2);
     INIT_PROC_EXT(EXT_debug_report, true, instance, CreateDebugReportCallbackEXT);
     INIT_PROC_EXT(EXT_debug_report, true, instance, DestroyDebugReportCallbackEXT);
     INIT_PROC_EXT(EXT_debug_report, true, instance, DebugReportMessageEXT);
diff --git a/vulkan/libvulkan/driver_gen.h b/vulkan/libvulkan/driver_gen.h
index 99dc889..14c3aba 100644
--- a/vulkan/libvulkan/driver_gen.h
+++ b/vulkan/libvulkan/driver_gen.h
@@ -69,6 +69,7 @@
     PFN_vkCreateDevice CreateDevice;
     PFN_vkEnumerateDeviceExtensionProperties EnumerateDeviceExtensionProperties;
     PFN_vkEnumeratePhysicalDeviceGroups EnumeratePhysicalDeviceGroups;
+    PFN_vkGetPhysicalDeviceProperties2 GetPhysicalDeviceProperties2;
     PFN_vkCreateDebugReportCallbackEXT CreateDebugReportCallbackEXT;
     PFN_vkDestroyDebugReportCallbackEXT DestroyDebugReportCallbackEXT;
     PFN_vkDebugReportMessageEXT DebugReportMessageEXT;