Merge "Add retries to vibrator HAL controller"
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 8173c89..5db44c7 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -58,6 +58,14 @@
     },
     {
       "name": "libsurfaceflinger_unittest"
+    },
+    {
+      "name": "CtsGraphicsTestCases",
+      "options": [
+        {
+          "include-filter": "android.graphics.cts.VulkanPreTransformTest"
+        }
+      ]
     }
   ]
 }
diff --git a/build/phone-hdpi-512-dalvik-heap.mk b/build/phone-hdpi-512-dalvik-heap.mk
index 102c3f1..f9a12ef 100644
--- a/build/phone-hdpi-512-dalvik-heap.mk
+++ b/build/phone-hdpi-512-dalvik-heap.mk
@@ -17,10 +17,10 @@
 # Provides overrides to configure the Dalvik heap for a standard high density
 # phone with around 512MB total RAM.
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=5m \
-    dalvik.vm.heapgrowthlimit=48m \
-    dalvik.vm.heapsize=128m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=2m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=5m \
+    dalvik.vm.heapgrowthlimit?=48m \
+    dalvik.vm.heapsize?=128m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=2m
diff --git a/build/phone-hdpi-dalvik-heap.mk b/build/phone-hdpi-dalvik-heap.mk
index cc0ac90..71cce74 100644
--- a/build/phone-hdpi-dalvik-heap.mk
+++ b/build/phone-hdpi-dalvik-heap.mk
@@ -16,9 +16,9 @@
 
 # Provides overrides to configure the Dalvik heap for a standard high density phone.
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=5m \
-    dalvik.vm.heapsize=32m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=2m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=5m \
+    dalvik.vm.heapsize?=32m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=2m
diff --git a/build/phone-xhdpi-1024-dalvik-heap.mk b/build/phone-xhdpi-1024-dalvik-heap.mk
index 221227d..a522a7d 100644
--- a/build/phone-xhdpi-1024-dalvik-heap.mk
+++ b/build/phone-xhdpi-1024-dalvik-heap.mk
@@ -16,10 +16,10 @@
 
 # Provides overrides to configure the Dalvik heap for a xhdpi phone
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=8m \
-    dalvik.vm.heapgrowthlimit=96m \
-    dalvik.vm.heapsize=256m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=8m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=8m \
+    dalvik.vm.heapgrowthlimit?=96m \
+    dalvik.vm.heapsize?=256m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=8m
diff --git a/build/phone-xhdpi-2048-dalvik-heap.mk b/build/phone-xhdpi-2048-dalvik-heap.mk
index 7ccfc13..f38d2f2 100644
--- a/build/phone-xhdpi-2048-dalvik-heap.mk
+++ b/build/phone-xhdpi-2048-dalvik-heap.mk
@@ -17,10 +17,10 @@
 # Provides overrides to configure the Dalvik heap for a 2GB phone
 # 192m of RAM gives enough space for 5 8 megapixel camera bitmaps in RAM.
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=8m \
-    dalvik.vm.heapgrowthlimit=192m \
-    dalvik.vm.heapsize=512m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=8m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=8m \
+    dalvik.vm.heapgrowthlimit?=192m \
+    dalvik.vm.heapsize?=512m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=8m
diff --git a/build/phone-xhdpi-4096-dalvik-heap.mk b/build/phone-xhdpi-4096-dalvik-heap.mk
index 2b84841..a6ff5a8 100644
--- a/build/phone-xhdpi-4096-dalvik-heap.mk
+++ b/build/phone-xhdpi-4096-dalvik-heap.mk
@@ -16,10 +16,10 @@
 
 # Provides overrides to configure the Dalvik heap for a 4GB phone
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=8m \
-    dalvik.vm.heapgrowthlimit=192m \
-    dalvik.vm.heapsize=512m \
-    dalvik.vm.heaptargetutilization=0.6 \
-    dalvik.vm.heapminfree=8m \
-    dalvik.vm.heapmaxfree=16m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=8m \
+    dalvik.vm.heapgrowthlimit?=192m \
+    dalvik.vm.heapsize?=512m \
+    dalvik.vm.heaptargetutilization?=0.6 \
+    dalvik.vm.heapminfree?=8m \
+    dalvik.vm.heapmaxfree?=16m
diff --git a/build/phone-xhdpi-6144-dalvik-heap.mk b/build/phone-xhdpi-6144-dalvik-heap.mk
index 2bacc4a..f08830b 100644
--- a/build/phone-xhdpi-6144-dalvik-heap.mk
+++ b/build/phone-xhdpi-6144-dalvik-heap.mk
@@ -16,10 +16,10 @@
 
 # Provides overrides to configure the Dalvik heap for a 6GB phone
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=16m \
-    dalvik.vm.heapgrowthlimit=256m \
-    dalvik.vm.heapsize=512m \
-    dalvik.vm.heaptargetutilization=0.5 \
-    dalvik.vm.heapminfree=8m \
-    dalvik.vm.heapmaxfree=32m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=16m \
+    dalvik.vm.heapgrowthlimit?=256m \
+    dalvik.vm.heapsize?=512m \
+    dalvik.vm.heaptargetutilization?=0.5 \
+    dalvik.vm.heapminfree?=8m \
+    dalvik.vm.heapmaxfree?=32m
diff --git a/build/tablet-10in-xhdpi-2048-dalvik-heap.mk b/build/tablet-10in-xhdpi-2048-dalvik-heap.mk
index 1721fcc..48c6ea6 100644
--- a/build/tablet-10in-xhdpi-2048-dalvik-heap.mk
+++ b/build/tablet-10in-xhdpi-2048-dalvik-heap.mk
@@ -16,10 +16,10 @@
 
 # Provides overrides to configure the Dalvik heap for a standard tablet device.
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=16m \
-    dalvik.vm.heapgrowthlimit=192m \
-    dalvik.vm.heapsize=512m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=8m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=16m \
+    dalvik.vm.heapgrowthlimit?=192m \
+    dalvik.vm.heapsize?=512m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=8m
diff --git a/build/tablet-7in-hdpi-1024-dalvik-heap.mk b/build/tablet-7in-hdpi-1024-dalvik-heap.mk
index 7fd34b5..d0027dc 100644
--- a/build/tablet-7in-hdpi-1024-dalvik-heap.mk
+++ b/build/tablet-7in-hdpi-1024-dalvik-heap.mk
@@ -16,10 +16,10 @@
 
 # Provides overrides to configure the Dalvik heap for a standard tablet device.
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=8m \
-    dalvik.vm.heapgrowthlimit=80m \
-    dalvik.vm.heapsize=384m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=8m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=8m \
+    dalvik.vm.heapgrowthlimit?=80m \
+    dalvik.vm.heapsize?=384m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=8m
diff --git a/build/tablet-7in-xhdpi-2048-dalvik-heap.mk b/build/tablet-7in-xhdpi-2048-dalvik-heap.mk
index e0f20c1..7c06b4b 100644
--- a/build/tablet-7in-xhdpi-2048-dalvik-heap.mk
+++ b/build/tablet-7in-xhdpi-2048-dalvik-heap.mk
@@ -16,10 +16,10 @@
 
 # Provides overrides to configure the Dalvik heap for a 320dpi 7" tablet device.
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=16m \
-    dalvik.vm.heapgrowthlimit=192m \
-    dalvik.vm.heapsize=512m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=8m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=16m \
+    dalvik.vm.heapgrowthlimit?=192m \
+    dalvik.vm.heapsize?=512m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=8m
diff --git a/build/tablet-dalvik-heap.mk b/build/tablet-dalvik-heap.mk
index f577fb8..1688665 100644
--- a/build/tablet-dalvik-heap.mk
+++ b/build/tablet-dalvik-heap.mk
@@ -16,10 +16,10 @@
 
 # Provides overrides to configure the Dalvik heap for a standard tablet device.
 
-PRODUCT_PROPERTY_OVERRIDES += \
-    dalvik.vm.heapstartsize=5m \
-    dalvik.vm.heapgrowthlimit=48m \
-    dalvik.vm.heapsize=256m \
-    dalvik.vm.heaptargetutilization=0.75 \
-    dalvik.vm.heapminfree=512k \
-    dalvik.vm.heapmaxfree=2m
+PRODUCT_VENDOR_PROPERTIES += \
+    dalvik.vm.heapstartsize?=5m \
+    dalvik.vm.heapgrowthlimit?=48m \
+    dalvik.vm.heapsize?=256m \
+    dalvik.vm.heaptargetutilization?=0.75 \
+    dalvik.vm.heapminfree?=512k \
+    dalvik.vm.heapmaxfree?=2m
diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp
index ead491e..4058934 100644
--- a/cmds/dumpstate/Android.bp
+++ b/cmds/dumpstate/Android.bp
@@ -152,6 +152,8 @@
         "tests/dumpstate_smoke_test.cpp",
     ],
     static_libs: ["libgmock"],
+    test_config: "dumpstate_smoke_test.xml",
+    test_suites: ["device-tests"],
 }
 
 
diff --git a/cmds/dumpstate/TEST_MAPPING b/cmds/dumpstate/TEST_MAPPING
index 083944f..8b03cfd 100644
--- a/cmds/dumpstate/TEST_MAPPING
+++ b/cmds/dumpstate/TEST_MAPPING
@@ -1,7 +1,21 @@
 {
   "presubmit": [
+    // TODO(159590499) add BugreportManagerTestCases
+    {
+      "name": "dumpstate_smoke_test"
+    },
     {
       "name": "dumpstate_test"
     }
+  ],
+  "postsubmit": [
+    {
+      "name": "BugreportManagerTestCases"
+    }
+  ],
+  "imports": [
+    {
+      "path": "frameworks/base/packages/Shell"
+    }
   ]
-}
\ No newline at end of file
+}
diff --git a/cmds/dumpstate/dumpstate_smoke_test.xml b/cmds/dumpstate/dumpstate_smoke_test.xml
new file mode 100644
index 0000000..0aff200
--- /dev/null
+++ b/cmds/dumpstate/dumpstate_smoke_test.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 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.
+-->
+<configuration description="Config for dumpstate_smoke_test">
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-native" />
+
+    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="dumpstate_smoke_test->/data/local/tmp/dumpstate_smoke_test" />
+    </target_preparer>
+
+    <test class="com.android.tradefed.testtype.GTest" >
+        <option name="native-test-device-path" value="/data/local/tmp" />
+        <option name="module-name" value="dumpstate_smoke_test" />
+        <option name="native-test-timeout" value="600000" />
+    </test>
+</configuration>
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index 6f2d754..bb0e5ad 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -209,13 +209,12 @@
     static std::shared_ptr<std::vector<SectionInfo>> sections;
     static Dumpstate& ds;
     static std::chrono::milliseconds duration;
-    static void SetUpTestCase() {
+    static void GenerateBugreport() {
         // clang-format off
         char* argv[] = {
             (char*)"dumpstate",
             (char*)"-d",
-            (char*)"-z",
-            (char*)"-B"
+            (char*)"-z"
         };
         // clang-format on
         sp<DumpstateListener> listener(new DumpstateListener(dup(fileno(stdout)), sections));
@@ -236,20 +235,20 @@
 std::chrono::milliseconds ZippedBugreportGenerationTest::duration = 0s;
 
 TEST_F(ZippedBugreportGenerationTest, IsGeneratedWithoutErrors) {
+    GenerateBugreport();
     EXPECT_EQ(access(getZipFilePath().c_str(), F_OK), 0);
 }
 
-TEST_F(ZippedBugreportGenerationTest, Is3MBto30MBinSize) {
+TEST_F(ZippedBugreportGenerationTest, Is3MBMBinSize) {
     struct stat st;
     EXPECT_EQ(stat(getZipFilePath().c_str(), &st), 0);
     EXPECT_GE(st.st_size, 3000000 /* 3MB */);
-    EXPECT_LE(st.st_size, 30000000 /* 30MB */);
 }
 
-TEST_F(ZippedBugreportGenerationTest, TakesBetween30And150Seconds) {
+TEST_F(ZippedBugreportGenerationTest, TakesBetween30And300Seconds) {
     EXPECT_GE(duration, 30s) << "Expected completion in more than 30s. Actual time "
                              << duration.count() << " s.";
-    EXPECT_LE(duration, 150s) << "Expected completion in less than 150s. Actual time "
+    EXPECT_LE(duration, 300s) << "Expected completion in less than 300s. Actual time "
                               << duration.count() << " s.";
 }
 
@@ -266,7 +265,8 @@
         CloseArchive(handle);
     }
 
-    void FileExists(const char* filename, uint32_t minsize, uint32_t maxsize) {
+    void FileExists(const char* filename, uint32_t minsize,
+                    uint32_t maxsize = std::numeric_limits<uint32_t>::max()) {
         ZipEntry entry;
         GetEntry(handle, filename, &entry);
         EXPECT_GT(entry.uncompressed_length, minsize);
@@ -285,7 +285,7 @@
                     main_entry.uncompressed_length);
 
     // contains main entry file
-    FileExists(bugreport_txt_name.c_str(), 1000000U, 50000000U);
+    FileExists(bugreport_txt_name.c_str(), 1000000U);
 }
 
 TEST_F(ZippedBugReportContentsTest, ContainsVersion) {
@@ -301,8 +301,9 @@
 }
 
 TEST_F(ZippedBugReportContentsTest, ContainsBoardSpecificFiles) {
-    FileExists("dumpstate_board.bin", 1000000U, 80000000U);
-    FileExists("dumpstate_board.txt", 100000U, 1000000U);
+    // TODO(b/160109027): cf_x86_phone-userdebug does not dump them.
+    // FileExists("dumpstate_board.bin", 1000000U, 80000000U);
+    // FileExists("dumpstate_board.txt", 100000U, 1000000U);
 }
 
 TEST_F(ZippedBugReportContentsTest, ContainsProtoFile) {
diff --git a/libs/adbd_auth/adbd_auth.cpp b/libs/adbd_auth/adbd_auth.cpp
index 5a0d3f6..dae6eeb 100644
--- a/libs/adbd_auth/adbd_auth.cpp
+++ b/libs/adbd_auth/adbd_auth.cpp
@@ -83,28 +83,28 @@
         InitFrameworkHandlers();
         epoll_fd_.reset(epoll_create1(EPOLL_CLOEXEC));
         if (epoll_fd_ == -1) {
-            PLOG(FATAL) << "failed to create epoll fd";
+            PLOG(FATAL) << "adbd_auth: failed to create epoll fd";
         }
 
         event_fd_.reset(eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK));
         if (event_fd_ == -1) {
-            PLOG(FATAL) << "failed to create eventfd";
+            PLOG(FATAL) << "adbd_auth: failed to create eventfd";
         }
 
         sock_fd_.reset(android_get_control_socket("adbd"));
         if (sock_fd_ == -1) {
-            PLOG(ERROR) << "failed to get adbd authentication socket";
+            PLOG(ERROR) << "adbd_auth: failed to get adbd authentication socket";
         } else {
             if (fcntl(sock_fd_.get(), F_SETFD, FD_CLOEXEC) != 0) {
-                PLOG(FATAL) << "failed to make adbd authentication socket cloexec";
+                PLOG(FATAL) << "adbd_auth: failed to make adbd authentication socket cloexec";
             }
 
             if (fcntl(sock_fd_.get(), F_SETFL, O_NONBLOCK) != 0) {
-                PLOG(FATAL) << "failed to make adbd authentication socket nonblocking";
+                PLOG(FATAL) << "adbd_auth: failed to make adbd authentication socket nonblocking";
             }
 
             if (listen(sock_fd_.get(), 4) != 0) {
-                PLOG(FATAL) << "failed to listen on adbd authentication socket";
+                PLOG(FATAL) << "adbd_auth: failed to listen on adbd authentication socket";
             }
         }
     }
@@ -146,7 +146,7 @@
             struct epoll_event event;
             event.events = EPOLLIN;
             if (!output_queue_.empty()) {
-                LOG(INFO) << "marking framework writable";
+                LOG(INFO) << "adbd_auth: marking framework writable";
                 event.events |= EPOLLOUT;
             }
             event.data.u64 = kEpollConstFramework;
@@ -155,7 +155,7 @@
     }
 
     void ReplaceFrameworkFd(unique_fd new_fd) REQUIRES(mutex_) {
-        LOG(INFO) << "received new framework fd " << new_fd.get()
+        LOG(INFO) << "adbd_auth: received new framework fd " << new_fd.get()
                   << " (current = " << framework_fd_.get() << ")";
 
         // If we already had a framework fd, clean up after ourselves.
@@ -170,7 +170,7 @@
             struct epoll_event event;
             event.events = EPOLLIN;
             if (!output_queue_.empty()) {
-                LOG(INFO) << "marking framework writable";
+                LOG(INFO) << "adbd_auth: marking framework writable";
                 event.events |= EPOLLOUT;
             }
             event.data.u64 = kEpollConstFramework;
@@ -180,10 +180,10 @@
     }
 
     void HandlePacket(std::string_view packet) EXCLUDES(mutex_) {
-        LOG(INFO) << "received packet: " << packet;
+        LOG(INFO) << "adbd_auth: received packet: " << packet;
 
         if (packet.size() < 2) {
-            LOG(ERROR) << "received packet of invalid length";
+            LOG(ERROR) << "adbd_auth: received packet of invalid length";
             std::lock_guard<std::mutex> lock(mutex_);
             ReplaceFrameworkFd(unique_fd());
         }
@@ -197,7 +197,7 @@
             }
         }
         if (!handled_packet) {
-            LOG(ERROR) << "unhandled packet: " << packet;
+            LOG(ERROR) << "adbd_auth: unhandled packet: " << packet;
             std::lock_guard<std::mutex> lock(mutex_);
             ReplaceFrameworkFd(unique_fd());
         }
@@ -206,12 +206,18 @@
     void AllowUsbDevice(std::string_view buf) EXCLUDES(mutex_) {
         std::lock_guard<std::mutex> lock(mutex_);
         CHECK(buf.empty());
-        CHECK(dispatched_prompt_.has_value());
-        auto& [id, key, arg] = *dispatched_prompt_;
-        keys_.emplace(id, std::move(key));
 
-        callbacks_.key_authorized(arg, id);
-        dispatched_prompt_ = std::nullopt;
+        if (dispatched_prompt_.has_value()) {
+            // It's possible for the framework to send us a response without our having sent a
+            // request to it: e.g. if adbd restarts while we have a pending request.
+            auto& [id, key, arg] = *dispatched_prompt_;
+            keys_.emplace(id, std::move(key));
+
+            callbacks_.key_authorized(arg, id);
+            dispatched_prompt_ = std::nullopt;
+        } else {
+            LOG(WARNING) << "adbd_auth: received authorization for unknown prompt, ignoring";
+        }
 
         // We need to dispatch pending prompts here upon success as well,
         // since we might have multiple queued prompts.
@@ -273,14 +279,14 @@
             iovs[2].iov_base = p->public_key.data();
             iovs[2].iov_len = p->public_key.size();
         } else {
-            LOG(FATAL) << "unhandled packet type?";
+            LOG(FATAL) << "adbd_auth: unhandled packet type?";
         }
 
         output_queue_.pop_front();
 
         ssize_t rc = writev(framework_fd_.get(), iovs, iovcnt);
         if (rc == -1 && errno != EAGAIN && errno != EWOULDBLOCK) {
-            PLOG(ERROR) << "failed to write to framework fd";
+            PLOG(ERROR) << "adbd_auth: failed to write to framework fd";
             ReplaceFrameworkFd(unique_fd());
             return false;
         }
@@ -290,7 +296,7 @@
 
     void Run() {
         if (sock_fd_ == -1) {
-            LOG(ERROR) << "adbd authentication socket unavailable, disabling user prompts";
+            LOG(ERROR) << "adbd_auth: socket unavailable, disabling user prompts";
         } else {
             struct epoll_event event;
             event.events = EPOLLIN;
@@ -309,9 +315,9 @@
             struct epoll_event events[3];
             int rc = TEMP_FAILURE_RETRY(epoll_wait(epoll_fd_.get(), events, 3, -1));
             if (rc == -1) {
-                PLOG(FATAL) << "epoll_wait failed";
+                PLOG(FATAL) << "adbd_auth: epoll_wait failed";
             } else if (rc == 0) {
-                LOG(FATAL) << "epoll_wait returned 0";
+                LOG(FATAL) << "adbd_auth: epoll_wait returned 0";
             }
 
             bool restart = false;
@@ -326,7 +332,7 @@
                         unique_fd new_framework_fd(accept4(sock_fd_.get(), nullptr, nullptr,
                                                            SOCK_CLOEXEC | SOCK_NONBLOCK));
                         if (new_framework_fd == -1) {
-                            PLOG(FATAL) << "failed to accept framework fd";
+                            PLOG(FATAL) << "adbd_auth: failed to accept framework fd";
                         }
 
                         LOG(INFO) << "adbd_auth: received a new framework connection";
@@ -344,7 +350,8 @@
                         uint64_t dummy;
                         int rc = TEMP_FAILURE_RETRY(read(event_fd_.get(), &dummy, sizeof(dummy)));
                         if (rc != 8) {
-                            PLOG(FATAL) << "failed to read from eventfd (rc = " << rc << ")";
+                            PLOG(FATAL)
+                                    << "adbd_auth: failed to read from eventfd (rc = " << rc << ")";
                         }
 
                         std::lock_guard<std::mutex> lock(mutex_);
@@ -357,9 +364,9 @@
                         if (event.events & EPOLLIN) {
                             int rc = TEMP_FAILURE_RETRY(read(framework_fd_.get(), buf, sizeof(buf)));
                             if (rc == -1) {
-                                LOG(FATAL) << "failed to read from framework fd";
+                                LOG(FATAL) << "adbd_auth: failed to read from framework fd";
                             } else if (rc == 0) {
-                                LOG(INFO) << "hit EOF on framework fd";
+                                LOG(INFO) << "adbd_auth: hit EOF on framework fd";
                                 std::lock_guard<std::mutex> lock(mutex_);
                                 ReplaceFrameworkFd(unique_fd());
                             } else {
@@ -386,10 +393,10 @@
     void IteratePublicKeys(bool (*callback)(void*, const char*, size_t), void* opaque) {
         for (const auto& path : key_paths) {
             if (access(path, R_OK) == 0) {
-                LOG(INFO) << "Loading keys from " << path;
+                LOG(INFO) << "adbd_auth: loading keys from " << path;
                 std::string content;
                 if (!android::base::ReadFileToString(path, &content)) {
-                    PLOG(ERROR) << "Couldn't read " << path;
+                    PLOG(ERROR) << "adbd_auth: couldn't read " << path;
                     continue;
                 }
                 for (const auto& line : android::base::Split(content, "\n")) {
@@ -405,6 +412,7 @@
         uint64_t id = NextId();
 
         std::lock_guard<std::mutex> lock(mutex_);
+        LOG(INFO) << "adbd_auth: sending prompt with id " << id;
         pending_prompts_.emplace_back(id, public_key, arg);
         DispatchPendingPrompt();
         return id;
@@ -423,7 +431,7 @@
         std::lock_guard<std::mutex> lock(mutex_);
         auto it = keys_.find(id);
         if (it == keys_.end()) {
-            LOG(DEBUG) << "couldn't find public key to notify disconnection, skipping";
+            LOG(DEBUG) << "adbd_auth: couldn't find public key to notify disconnection, skipping";
             return;
         }
         output_queue_.emplace_back(AdbdAuthPacketDisconnected{.public_key = std::move(it->second)});
@@ -446,7 +454,8 @@
         std::lock_guard<std::mutex> lock(mutex_);
         auto it = keys_.find(id);
         if (it == keys_.end()) {
-            LOG(DEBUG) << "couldn't find public key to notify disconnection of tls device, skipping";
+            LOG(DEBUG) << "adbd_auth: couldn't find public key to notify disconnection of tls "
+                          "device, skipping";
             return;
         }
         output_queue_.emplace_back(AdbdPacketTlsDeviceDisconnected{
@@ -461,9 +470,9 @@
         uint64_t value = 1;
         ssize_t rc = write(event_fd_.get(), &value, sizeof(value));
         if (rc == -1) {
-            PLOG(FATAL) << "write to eventfd failed";
+            PLOG(FATAL) << "adbd_auth: write to eventfd failed";
         } else if (rc != sizeof(value)) {
-            LOG(FATAL) << "write to eventfd returned short (" << rc << ")";
+            LOG(FATAL) << "adbd_auth: write to eventfd returned short (" << rc << ")";
         }
     }
 
@@ -516,8 +525,9 @@
     if (callbacks->version == 1) {
         return new AdbdAuthContext(reinterpret_cast<AdbdAuthCallbacksV1*>(callbacks));
     } else {
-      LOG(ERROR) << "received unknown AdbdAuthCallbacks version " << callbacks->version;
-      return nullptr;
+        LOG(ERROR) << "adbd_auth: received unknown AdbdAuthCallbacks version "
+                   << callbacks->version;
+        return nullptr;
     }
 }
 
@@ -545,7 +555,12 @@
 
 void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len,
                            void* opaque) {
-    ctx->PromptUser(std::string_view(public_key, len), opaque);
+    adbd_auth_prompt_user_with_id(ctx, public_key, len, opaque);
+}
+
+uint64_t adbd_auth_prompt_user_with_id(AdbdAuthContext* ctx, const char* public_key, size_t len,
+                                       void* opaque) {
+    return ctx->PromptUser(std::string_view(public_key, len), opaque);
 }
 
 uint64_t adbd_auth_tls_device_connected(AdbdAuthContext* ctx,
diff --git a/libs/adbd_auth/include/adbd_auth.h b/libs/adbd_auth/include/adbd_auth.h
index 6ee3166..8f834df 100644
--- a/libs/adbd_auth/include/adbd_auth.h
+++ b/libs/adbd_auth/include/adbd_auth.h
@@ -122,9 +122,23 @@
  * @param len the length of the public_key argument
  * @param arg an opaque userdata argument
  */
-void adbd_auth_prompt_user(AdbdAuthContext* ctx,
-                           const char* public_key,
-                           size_t len, void* opaque) __INTRODUCED_IN(30);
+void adbd_auth_prompt_user(AdbdAuthContext* ctx, const char* public_key, size_t len, void* opaque)
+        __INTRODUCED_IN(30);
+
+/**
+ * Prompt the user to authorize a public key.
+ *
+ * When this happens, a callback will be run on the auth thread with the result.
+ *
+ * @param ctx the AdbdAuthContext
+ * @param public_key the RSA public key to prompt user with
+ * @param len the length of the public_key argument
+ * @param arg an opaque userdata argument
+ * @return a unique id which will be returned via callback
+ */
+__attribute__((weak)) uint64_t adbd_auth_prompt_user_with_id(AdbdAuthContext* ctx,
+                                                             const char* public_key, size_t len,
+                                                             void* opaque) __INTRODUCED_IN(30);
 
 /**
  * Let system_server know that a TLS device has connected.
diff --git a/libs/adbd_auth/libadbd_auth.map.txt b/libs/adbd_auth/libadbd_auth.map.txt
index 5857ecb..7584ca3 100644
--- a/libs/adbd_auth/libadbd_auth.map.txt
+++ b/libs/adbd_auth/libadbd_auth.map.txt
@@ -7,6 +7,7 @@
     adbd_auth_notify_auth; # apex introduced=30
     adbd_auth_notify_disconnect; # apex introduced=30
     adbd_auth_prompt_user; # apex introduced=30
+    adbd_auth_prompt_user_with_id; # apex introduced=30
     adbd_auth_tls_device_connected; # apex introduced=30
     adbd_auth_tls_device_disconnected; # apex introduced=30
     adbd_auth_get_max_version; # apex introduced=30
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index db4aba8..b24a577 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -17,6 +17,8 @@
     export_include_dirs: ["include"],
     vendor_available: true,
     host_supported: true,
+    // TODO(b/153609531): remove when no longer needed.
+    native_bridge_supported: true,
 
     header_libs: [
         "libbase_headers",
@@ -62,6 +64,8 @@
     },
     double_loadable: true,
     host_supported: true,
+    // TODO(b/153609531): remove when no longer needed.
+    native_bridge_supported: true,
 
     // TODO(b/31559095): get headers from bionic on host
     include_dirs: [
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 166c1d8..5ea56de 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -2667,7 +2667,7 @@
 
     releaseObjects();
 
-    if (data) {
+    if (data || desired == 0) {
         LOG_ALLOC("Parcel %p: restart from %zu to %zu capacity", this, mDataCapacity, desired);
         pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
         gParcelGlobalAllocSize += desired;
diff --git a/libs/binder/ndk/include_platform/android/binder_parcel_platform.h b/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
index ac46cb8..114a781 100644
--- a/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
+++ b/libs/binder/ndk/include_platform/android/binder_parcel_platform.h
@@ -20,6 +20,10 @@
 
 __BEGIN_DECLS
 
+#if defined(__ANDROID_APEX__) || defined(__ANDROID_VNDK__)
+#error this is only for platform code
+#endif
+
 /**
  * Gets whether or not FDs are allowed by this AParcel
  *
@@ -29,4 +33,4 @@
  */
 bool AParcel_getAllowFds(const AParcel*);
 
-__END_DECLS
\ No newline at end of file
+__END_DECLS
diff --git a/libs/gui/OWNERS b/libs/gui/OWNERS
index cbb4b97..ecccf29 100644
--- a/libs/gui/OWNERS
+++ b/libs/gui/OWNERS
@@ -13,3 +13,13 @@
 vishnun@google.com
 
 per-file EndToEndNativeInputTest.cpp = svv@google.com
+
+# BufferQueue is feature-frozen
+per-file BufferQueue* = set noparent
+per-file BufferQueue* = jreck@google.com, sumir@google.com, alecmouri@google.com
+per-file IGraphicBuffer* = set noparent
+per-file IGraphicBuffer* = jreck@google.com, sumir@google.com, alecmouri@google.com
+per-file include/gui/BufferQueue* = set noparent
+per-file include/gui/BufferQueue* = jreck@google.com, sumir@google.com, alecmouri@google.com
+per-file include/gui/IGraphicBuffer* = set noparent
+per-file include/gui/IGraphicBuffer* = jreck@google.com, sumir@google.com, alecmouri@google.com
\ No newline at end of file
diff --git a/libs/gui/bufferqueue/OWNERS b/libs/gui/bufferqueue/OWNERS
index cbe9317..615dd79 100644
--- a/libs/gui/bufferqueue/OWNERS
+++ b/libs/gui/bufferqueue/OWNERS
@@ -1,5 +1,4 @@
-chz@google.com
-lajos@google.com
-pawin@google.com
-taklee@google.com
-wonsik@google.com
+# BufferQueue is feature-frozen
+jreck@google.com
+sumir@google.com
+alecmouri@google.com
\ No newline at end of file
diff --git a/libs/vr/libpdx/fuzz/Android.bp b/libs/vr/libpdx/fuzz/Android.bp
index 3490775..8ab09f3 100644
--- a/libs/vr/libpdx/fuzz/Android.bp
+++ b/libs/vr/libpdx/fuzz/Android.bp
@@ -15,9 +15,6 @@
     shared_libs: [
         "libutils",
         "liblog",
+	"libcutils",
     ],
-    fuzz_config: {
-        fuzz_on_haiku_host: false,
-        fuzz_on_haiku_device: false,
-    },
 }
diff --git a/services/gpuservice/Android.bp b/services/gpuservice/Android.bp
index 04fe1e6..1bcaab4 100644
--- a/services/gpuservice/Android.bp
+++ b/services/gpuservice/Android.bp
@@ -22,6 +22,7 @@
         "libcutils",
         "libgfxstats",
         "libgpumem",
+        "libgpumemtracer",
         "libgraphicsenv",
         "liblog",
         "libutils",
diff --git a/services/gpuservice/GpuService.cpp b/services/gpuservice/GpuService.cpp
index bad5637..18c819f 100644
--- a/services/gpuservice/GpuService.cpp
+++ b/services/gpuservice/GpuService.cpp
@@ -27,10 +27,13 @@
 #include <gpumem/GpuMem.h>
 #include <gpustats/GpuStats.h>
 #include <private/android_filesystem_config.h>
+#include <tracing/GpuMemTracer.h>
 #include <utils/String8.h>
 #include <utils/Trace.h>
 #include <vkjson.h>
 
+#include <thread>
+
 namespace android {
 
 using base::StringAppendF;
@@ -46,8 +49,14 @@
 const char* const GpuService::SERVICE_NAME = "gpu";
 
 GpuService::GpuService()
-      : mGpuMem(std::make_unique<GpuMem>()), mGpuStats(std::make_unique<GpuStats>()) {
-    mGpuMem->initialize();
+      : mGpuMem(std::make_shared<GpuMem>()),
+        mGpuStats(std::make_unique<GpuStats>()),
+        mGpuMemTracer(std::make_unique<GpuMemTracer>()) {
+    std::thread asyncInitThread([this]() {
+        mGpuMem->initialize();
+        mGpuMemTracer->initialize(mGpuMem);
+    });
+    asyncInitThread.detach();
 };
 
 void GpuService::setGpuStats(const std::string& driverPackageName,
diff --git a/services/gpuservice/GpuService.h b/services/gpuservice/GpuService.h
index 9a0460d..43faa3e 100644
--- a/services/gpuservice/GpuService.h
+++ b/services/gpuservice/GpuService.h
@@ -30,6 +30,7 @@
 
 class GpuMem;
 class GpuStats;
+class GpuMemTracer;
 
 class GpuService : public BnGpuService, public PriorityDumper {
 public:
@@ -75,8 +76,9 @@
     /*
      * Attributes
      */
-    std::unique_ptr<GpuMem> mGpuMem;
+    std::shared_ptr<GpuMem> mGpuMem;
     std::unique_ptr<GpuStats> mGpuStats;
+    std::unique_ptr<GpuMemTracer> mGpuMemTracer;
     std::string developerDriverPath;
 };
 
diff --git a/services/gpuservice/gpumem/GpuMem.cpp b/services/gpuservice/gpumem/GpuMem.cpp
index 1d4b524..9b4053b 100644
--- a/services/gpuservice/gpumem/GpuMem.cpp
+++ b/services/gpuservice/gpumem/GpuMem.cpp
@@ -24,6 +24,7 @@
 #include <libbpf.h>
 #include <libbpf_android.h>
 #include <log/log.h>
+#include <unistd.h>
 #include <utils/Trace.h>
 
 #include <unordered_map>
@@ -47,11 +48,17 @@
         return;
     }
 
+    // TODO(http://b/159963505): Figure out a nicer way to wait until GPU driver loaded.
     // Attach the program to the tracepoint, and the tracepoint is automatically enabled here.
-    if (bpf_attach_tracepoint(fd, kGpuMemTraceGroup, kGpuMemTotalTracepoint) < 0) {
-        ALOGE("Failed to attach bpf program to %s/%s tracepoint", kGpuMemTraceGroup,
-              kGpuMemTotalTracepoint);
-        return;
+    int count = 0;
+    while (bpf_attach_tracepoint(fd, kGpuMemTraceGroup, kGpuMemTotalTracepoint) < 0) {
+        if (++count > kGpuWaitTimeout) {
+            ALOGE("Failed to attach bpf program to %s/%s tracepoint", kGpuMemTraceGroup,
+                  kGpuMemTotalTracepoint);
+            return;
+        }
+        // Retry until GPU driver loaded or timeout.
+        sleep(1);
     }
 
     // Use the read-only wrapper BpfMapRO to properly retrieve the read-only map.
@@ -61,6 +68,8 @@
         return;
     }
     setGpuMemTotalMap(map);
+
+    mInitialized.store(true);
 }
 
 void GpuMem::setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map) {
@@ -71,7 +80,7 @@
 void GpuMem::dump(const Vector<String16>& /* args */, std::string* result) {
     ATRACE_CALL();
 
-    if (!mGpuMemTotalMap.isValid()) {
+    if (!mInitialized.load() || !mGpuMemTotalMap.isValid()) {
         result->append("Failed to initialize GPU memory eBPF\n");
         return;
     }
diff --git a/services/gpuservice/gpumem/include/gpumem/GpuMem.h b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
index 6d0322a..49a9f95 100644
--- a/services/gpuservice/gpumem/include/gpumem/GpuMem.h
+++ b/services/gpuservice/gpumem/include/gpumem/GpuMem.h
@@ -31,6 +31,29 @@
     void initialize();
     // dumpsys interface
     void dump(const Vector<String16>& args, std::string* result);
+    bool isInitialized() { return mInitialized.load(); }
+
+    // Traverse the map and send each value read back to the callback function.
+    // Used for tracing.
+    template <typename lambda>
+    void traceGpuMemTotals(lambda tracerCallback) {
+        auto res = mGpuMemTotalMap.getFirstKey();
+        if (!res.ok()) return;
+        uint64_t key = res.value();
+        while (true) {
+            uint32_t gpu_id = key >> 32;
+            uint32_t pid = key;
+
+            res = mGpuMemTotalMap.readValue(key);
+            if (!res.ok()) break;
+            uint64_t size = res.value();
+
+            tracerCallback(gpu_id, pid, size);
+            res = mGpuMemTotalMap.getNextKey(key);
+            if (!res.ok()) break;
+            key = res.value();
+        }
+    }
 
 private:
     // Friend class for testing.
@@ -39,6 +62,8 @@
     // set gpu memory total map
     void setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map);
 
+    // indicate whether ebpf has been initialized
+    std::atomic<bool> mInitialized = false;
     // bpf map for GPU memory total data
     android::bpf::BpfMap<uint64_t, uint64_t> mGpuMemTotalMap;
 
@@ -51,6 +76,8 @@
             "/sys/fs/bpf/prog_gpu_mem_tracepoint_gpu_mem_gpu_mem_total";
     // pinned gpu memory total bpf map path in bpf sysfs
     static constexpr char kGpuMemTotalMapPath[] = "/sys/fs/bpf/map_gpu_mem_gpu_mem_total_map";
+    // 30 seconds timeout for trying to attach bpf program to tracepoint
+    static constexpr int kGpuWaitTimeout = 30;
 };
 
 } // namespace android
diff --git a/services/gpuservice/tests/unittests/GpuMemTest.cpp b/services/gpuservice/tests/unittests/GpuMemTest.cpp
index 6ba304c..abaf30a 100644
--- a/services/gpuservice/tests/unittests/GpuMemTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuMemTest.cpp
@@ -62,6 +62,7 @@
 
         mGpuMem = std::make_unique<GpuMem>();
         mTestableGpuMem = TestableGpuMem(mGpuMem.get());
+        mTestableGpuMem.setInitialized();
         errno = 0;
         mTestMap = bpf::BpfMap<uint64_t, uint64_t>(BPF_MAP_TYPE_HASH, TEST_MAP_SIZE,
                                                    BPF_F_NO_PREALLOC);
diff --git a/services/gpuservice/tests/unittests/TestableGpuMem.h b/services/gpuservice/tests/unittests/TestableGpuMem.h
index 0e4b01c..6c8becb 100644
--- a/services/gpuservice/tests/unittests/TestableGpuMem.h
+++ b/services/gpuservice/tests/unittests/TestableGpuMem.h
@@ -26,6 +26,8 @@
     TestableGpuMem() = default;
     explicit TestableGpuMem(GpuMem *gpuMem) : mGpuMem(gpuMem) {}
 
+    void setInitialized() { mGpuMem->mInitialized.store(true); }
+
     void setGpuMemTotalMap(bpf::BpfMap<uint64_t, uint64_t>& map) {
         mGpuMem->setGpuMemTotalMap(map);
     }
diff --git a/services/gpuservice/tracing/Android.bp b/services/gpuservice/tracing/Android.bp
new file mode 100644
index 0000000..919fed3
--- /dev/null
+++ b/services/gpuservice/tracing/Android.bp
@@ -0,0 +1,41 @@
+// Copyright 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_library_shared {
+    name: "libgpumemtracer",
+    srcs: [
+        "GpuMemTracer.cpp",
+    ],
+    shared_libs: [
+        "libgpumem",
+        "libbase",
+        "liblog",
+        "libutils",
+    ],
+    static_libs: [
+        "libperfetto_client_experimental",
+    ],
+    export_include_dirs: ["include"],
+    export_static_lib_headers: [
+        "libperfetto_client_experimental",
+    ],
+    cppflags: [
+        "-Wall",
+        "-Werror",
+        "-Wformat",
+        "-Wthread-safety",
+        "-Wunused",
+        "-Wunreachable-code",
+    ],
+}
diff --git a/services/gpuservice/tracing/GpuMemTracer.cpp b/services/gpuservice/tracing/GpuMemTracer.cpp
new file mode 100644
index 0000000..c9bfa57
--- /dev/null
+++ b/services/gpuservice/tracing/GpuMemTracer.cpp
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2020 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 "GpuMemTracer"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "tracing/GpuMemTracer.h"
+
+#include <gpumem/GpuMem.h>
+#include <perfetto/trace/android/gpu_mem_event.pbzero.h>
+#include <unistd.h>
+#include <utils/Timers.h>
+
+#include <algorithm>
+#include <thread>
+
+PERFETTO_DEFINE_DATA_SOURCE_STATIC_MEMBERS(android::GpuMemTracer::GpuMemDataSource);
+
+namespace android {
+
+std::mutex GpuMemTracer::sTraceMutex;
+std::condition_variable GpuMemTracer::sCondition;
+bool GpuMemTracer::sTraceStarted;
+
+void GpuMemTracer::initialize(std::shared_ptr<GpuMem> gpuMem) {
+    if (!gpuMem->isInitialized()) {
+        ALOGE("Cannot initialize GpuMemTracer before GpuMem");
+        return;
+    }
+    mGpuMem = gpuMem;
+    perfetto::TracingInitArgs args;
+    args.backends = perfetto::kSystemBackend;
+    // TODO(b/160016498): Find a better way to wait for traced
+    // Sleep for 30 seconds to make sure the data source is registered only
+    // after traced starts.
+    sleep(30);
+    perfetto::Tracing::Initialize(args);
+    registerDataSource();
+    std::thread tracerThread(&GpuMemTracer::threadLoop, this);
+    pthread_setname_np(tracerThread.native_handle(), "GpuMemTracerThread");
+    tracerThread.detach();
+}
+
+void GpuMemTracer::registerDataSource() {
+    perfetto::DataSourceDescriptor dsd;
+    dsd.set_name(kGpuMemDataSource);
+    GpuMemDataSource::Register(dsd);
+}
+
+void GpuMemTracer::threadLoop() {
+    while (true) {
+        {
+            std::unique_lock<std::mutex> lock(GpuMemTracer::sTraceMutex);
+            while (!sTraceStarted) {
+                sCondition.wait(lock);
+            }
+        }
+        traceInitialCounters();
+        {
+            std::lock_guard<std::mutex> lock(GpuMemTracer::sTraceMutex);
+            sTraceStarted = false;
+        }
+    }
+}
+
+void GpuMemTracer::traceInitialCounters() {
+    if (!mGpuMem->isInitialized()) {
+        // This should never happen.
+        ALOGE("Cannot trace without GpuMem initialization");
+        return;
+    }
+    mGpuMem->traceGpuMemTotals([](uint32_t gpuId, uint32_t pid, uint64_t size) {
+        GpuMemDataSource::Trace([&](GpuMemDataSource::TraceContext ctx) {
+            auto packet = ctx.NewTracePacket();
+            packet->set_timestamp(systemTime());
+            auto* event = packet->set_gpu_mem_total_event();
+            event->set_gpu_id(gpuId);
+            event->set_pid(pid);
+            event->set_size(size);
+        });
+    });
+    // Flush the TraceContext. The last packet in the above loop will go
+    // missing without this flush.
+    GpuMemDataSource::Trace([](GpuMemDataSource::TraceContext ctx) { ctx.Flush(); });
+}
+
+} // namespace android
diff --git a/services/gpuservice/tracing/include/tracing/GpuMemTracer.h b/services/gpuservice/tracing/include/tracing/GpuMemTracer.h
new file mode 100644
index 0000000..40deb4c
--- /dev/null
+++ b/services/gpuservice/tracing/include/tracing/GpuMemTracer.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2020 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 <perfetto/tracing.h>
+
+#include <mutex>
+
+namespace android {
+
+class GpuMem;
+
+class GpuMemTracer {
+public:
+    class GpuMemDataSource : public perfetto::DataSource<GpuMemDataSource> {
+        virtual void OnSetup(const SetupArgs&) override{};
+        virtual void OnStart(const StartArgs&) override {
+            std::unique_lock<std::mutex> lock(GpuMemTracer::sTraceMutex);
+            sTraceStarted = true;
+            sCondition.notify_all();
+        }
+        virtual void OnStop(const StopArgs&) override{};
+    };
+
+    ~GpuMemTracer() = default;
+
+    // Sets up the perfetto tracing backend and data source.
+    void initialize(std::shared_ptr<GpuMem>);
+    // Registers the data source with the perfetto backend. Called as part of initialize()
+    // and should not be called manually outside of tests. Public to allow for substituting a
+    // perfetto::kInProcessBackend in tests.
+    void registerDataSource();
+
+    static constexpr char kGpuMemDataSource[] = "android.gpu.memory";
+    static std::condition_variable sCondition;
+    static std::mutex sTraceMutex;
+    static bool sTraceStarted;
+
+private:
+    void traceInitialCounters();
+    void threadLoop();
+
+    std::shared_ptr<GpuMem> mGpuMem;
+};
+
+} // namespace android
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 91803c8..49f9c54 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3568,6 +3568,10 @@
 
 sp<InputWindowHandle> InputDispatcher::getWindowHandleLocked(
         const sp<IBinder>& windowHandleToken) const {
+    if (windowHandleToken == nullptr) {
+        return nullptr;
+    }
+
     for (auto& it : mWindowHandlesByDisplay) {
         const std::vector<sp<InputWindowHandle>> windowHandles = it.second;
         for (const sp<InputWindowHandle>& windowHandle : windowHandles) {
@@ -3583,7 +3587,8 @@
     for (auto& it : mWindowHandlesByDisplay) {
         const std::vector<sp<InputWindowHandle>> windowHandles = it.second;
         for (const sp<InputWindowHandle>& handle : windowHandles) {
-            if (handle->getToken() == windowHandle->getToken()) {
+            if (handle->getId() == windowHandle->getId() &&
+                handle->getToken() == windowHandle->getToken()) {
                 if (windowHandle->getInfo()->displayId != it.first) {
                     ALOGE("Found window %s in display %" PRId32
                           ", but it should belong to display %" PRId32,
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index f8d5351..0fa8787 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -335,7 +335,8 @@
     virtual void getReaderConfiguration(InputReaderConfiguration* outConfig) = 0;
 
     /* Gets a pointer controller associated with the specified cursor device (ie. a mouse). */
-    virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) = 0;
+    virtual std::shared_ptr<PointerControllerInterface> obtainPointerController(
+            int32_t deviceId) = 0;
 
     /* Notifies the input reader policy that some input devices have changed
      * and provides information about all current input devices.
diff --git a/services/inputflinger/include/PointerControllerInterface.h b/services/inputflinger/include/PointerControllerInterface.h
index 194c665..bffff88 100644
--- a/services/inputflinger/include/PointerControllerInterface.h
+++ b/services/inputflinger/include/PointerControllerInterface.h
@@ -33,7 +33,7 @@
  * The pointer controller is responsible for providing synchronization and for tracking
  * display orientation changes if needed.
  */
-class PointerControllerInterface : public virtual RefBase {
+class PointerControllerInterface {
 protected:
     PointerControllerInterface() { }
     virtual ~PointerControllerInterface() { }
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 657a134..d3441ac 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -390,8 +390,9 @@
     }
 }
 
-sp<PointerControllerInterface> InputReader::getPointerControllerLocked(int32_t deviceId) {
-    sp<PointerControllerInterface> controller = mPointerController.promote();
+std::shared_ptr<PointerControllerInterface> InputReader::getPointerControllerLocked(
+        int32_t deviceId) {
+    std::shared_ptr<PointerControllerInterface> controller = mPointerController.lock();
     if (controller == nullptr) {
         controller = mPolicy->obtainPointerController(deviceId);
         mPointerController = controller;
@@ -401,7 +402,7 @@
 }
 
 void InputReader::updatePointerDisplayLocked() {
-    sp<PointerControllerInterface> controller = mPointerController.promote();
+    std::shared_ptr<PointerControllerInterface> controller = mPointerController.lock();
     if (controller == nullptr) {
         return;
     }
@@ -424,7 +425,7 @@
 }
 
 void InputReader::fadePointerLocked() {
-    sp<PointerControllerInterface> controller = mPointerController.promote();
+    std::shared_ptr<PointerControllerInterface> controller = mPointerController.lock();
     if (controller != nullptr) {
         controller->fade(PointerControllerInterface::TRANSITION_GRADUAL);
     }
@@ -725,7 +726,8 @@
     mReader->fadePointerLocked();
 }
 
-sp<PointerControllerInterface> InputReader::ContextImpl::getPointerController(int32_t deviceId) {
+std::shared_ptr<PointerControllerInterface> InputReader::ContextImpl::getPointerController(
+        int32_t deviceId) {
     // lock is already held by the input loop
     return mReader->getPointerControllerLocked(deviceId);
 }
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 693ec30..108b9c2 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -17,19 +17,20 @@
 #ifndef _UI_INPUTREADER_INPUT_READER_H
 #define _UI_INPUTREADER_INPUT_READER_H
 
+#include <PointerControllerInterface.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
 #include "EventHub.h"
 #include "InputListener.h"
 #include "InputReaderBase.h"
 #include "InputReaderContext.h"
 #include "InputThread.h"
 
-#include <PointerControllerInterface.h>
-#include <utils/Condition.h>
-#include <utils/Mutex.h>
-
-#include <unordered_map>
-#include <vector>
-
 namespace android {
 
 class InputDevice;
@@ -104,7 +105,8 @@
         virtual void disableVirtualKeysUntil(nsecs_t time) override;
         virtual bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) override;
         virtual void fadePointer() override;
-        virtual sp<PointerControllerInterface> getPointerController(int32_t deviceId) override;
+        virtual std::shared_ptr<PointerControllerInterface> getPointerController(
+                int32_t deviceId) override;
         virtual void requestTimeoutAtTime(nsecs_t when) override;
         virtual int32_t bumpGeneration() override;
         virtual void getExternalStylusDevices(std::vector<InputDeviceInfo>& outDevices) override;
@@ -160,8 +162,8 @@
     void dispatchExternalStylusState(const StylusState& state);
 
     // The PointerController that is shared among all the input devices that need it.
-    wp<PointerControllerInterface> mPointerController;
-    sp<PointerControllerInterface> getPointerControllerLocked(int32_t deviceId);
+    std::weak_ptr<PointerControllerInterface> mPointerController;
+    std::shared_ptr<PointerControllerInterface> getPointerControllerLocked(int32_t deviceId);
     void updatePointerDisplayLocked();
     void fadePointerLocked();
 
diff --git a/services/inputflinger/reader/include/InputReaderContext.h b/services/inputflinger/reader/include/InputReaderContext.h
index 85701e4..ffb8d8c 100644
--- a/services/inputflinger/reader/include/InputReaderContext.h
+++ b/services/inputflinger/reader/include/InputReaderContext.h
@@ -46,7 +46,7 @@
     virtual bool shouldDropVirtualKey(nsecs_t now, int32_t keyCode, int32_t scanCode) = 0;
 
     virtual void fadePointer() = 0;
-    virtual sp<PointerControllerInterface> getPointerController(int32_t deviceId) = 0;
+    virtual std::shared_ptr<PointerControllerInterface> getPointerController(int32_t deviceId) = 0;
 
     virtual void requestTimeoutAtTime(nsecs_t when) = 0;
     virtual int32_t bumpGeneration() = 0;
diff --git a/services/inputflinger/reader/mapper/CursorInputMapper.h b/services/inputflinger/reader/mapper/CursorInputMapper.h
index f65ac39..05bbb26 100644
--- a/services/inputflinger/reader/mapper/CursorInputMapper.h
+++ b/services/inputflinger/reader/mapper/CursorInputMapper.h
@@ -106,7 +106,7 @@
 
     int32_t mOrientation;
 
-    sp<PointerControllerInterface> mPointerController;
+    std::shared_ptr<PointerControllerInterface> mPointerController;
 
     int32_t mButtonState;
     nsecs_t mDownTime;
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
index 030a846..b2e10d6 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.cpp
@@ -123,42 +123,15 @@
             if (rawAxisInfo.valid) {
                 // Map axis.
                 AxisInfo axisInfo;
-                bool explicitlyMapped = !getDeviceContext().mapAxis(abs, &axisInfo);
+                const bool explicitlyMapped = !getDeviceContext().mapAxis(abs, &axisInfo);
+
                 if (!explicitlyMapped) {
                     // Axis is not explicitly mapped, will choose a generic axis later.
                     axisInfo.mode = AxisInfo::MODE_NORMAL;
                     axisInfo.axis = -1;
                 }
 
-                // Apply flat override.
-                int32_t rawFlat =
-                        axisInfo.flatOverride < 0 ? rawAxisInfo.flat : axisInfo.flatOverride;
-
-                // Calculate scaling factors and limits.
-                Axis axis;
-                if (axisInfo.mode == AxisInfo::MODE_SPLIT) {
-                    float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue);
-                    float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue);
-                    axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, 0.0f, highScale,
-                                    0.0f, 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
-                                    rawAxisInfo.resolution * scale);
-                } else if (isCenteredAxis(axisInfo.axis)) {
-                    float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
-                    float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale;
-                    axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, offset, scale,
-                                    offset, -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
-                                    rawAxisInfo.resolution * scale);
-                } else {
-                    float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
-                    axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, 0.0f, scale,
-                                    0.0f, 0.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
-                                    rawAxisInfo.resolution * scale);
-                }
-
-                // To eliminate noise while the joystick is at rest, filter out small variations
-                // in axis values up front.
-                axis.filter = axis.fuzz ? axis.fuzz : axis.flat * 0.25f;
-
+                Axis axis = createAxis(axisInfo, rawAxisInfo, explicitlyMapped);
                 mAxes.add(abs, axis);
             }
         }
@@ -198,6 +171,40 @@
     }
 }
 
+JoystickInputMapper::Axis JoystickInputMapper::createAxis(const AxisInfo& axisInfo,
+                                                          const RawAbsoluteAxisInfo& rawAxisInfo,
+                                                          bool explicitlyMapped) {
+    // Apply flat override.
+    int32_t rawFlat = axisInfo.flatOverride < 0 ? rawAxisInfo.flat : axisInfo.flatOverride;
+
+    // Calculate scaling factors and limits.
+    Axis axis;
+    if (axisInfo.mode == AxisInfo::MODE_SPLIT) {
+        float scale = 1.0f / (axisInfo.splitValue - rawAxisInfo.minValue);
+        float highScale = 1.0f / (rawAxisInfo.maxValue - axisInfo.splitValue);
+        axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, 0.0f, highScale, 0.0f, 0.0f,
+                        1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
+                        rawAxisInfo.resolution * scale);
+    } else if (isCenteredAxis(axisInfo.axis)) {
+        float scale = 2.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
+        float offset = avg(rawAxisInfo.minValue, rawAxisInfo.maxValue) * -scale;
+        axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, offset, scale, offset,
+                        -1.0f, 1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
+                        rawAxisInfo.resolution * scale);
+    } else {
+        float scale = 1.0f / (rawAxisInfo.maxValue - rawAxisInfo.minValue);
+        axis.initialize(rawAxisInfo, axisInfo, explicitlyMapped, scale, 0.0f, scale, 0.0f, 0.0f,
+                        1.0f, rawFlat * scale, rawAxisInfo.fuzz * scale,
+                        rawAxisInfo.resolution * scale);
+    }
+
+    // To eliminate noise while the joystick is at rest, filter out small variations
+    // in axis values up front.
+    axis.filter = axis.fuzz ? axis.fuzz : axis.flat * 0.25f;
+
+    return axis;
+}
+
 bool JoystickInputMapper::haveAxis(int32_t axisId) {
     size_t numAxes = mAxes.size();
     for (size_t i = 0; i < numAxes; i++) {
diff --git a/services/inputflinger/reader/mapper/JoystickInputMapper.h b/services/inputflinger/reader/mapper/JoystickInputMapper.h
index 823a096..29d5652 100644
--- a/services/inputflinger/reader/mapper/JoystickInputMapper.h
+++ b/services/inputflinger/reader/mapper/JoystickInputMapper.h
@@ -86,6 +86,9 @@
         }
     };
 
+    static Axis createAxis(const AxisInfo& AxisInfo, const RawAbsoluteAxisInfo& rawAxisInfo,
+                           bool explicitlyMapped);
+
     // Axes indexed by raw ABS_* axis index.
     KeyedVector<int32_t, Axis> mAxes;
 
diff --git a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
index 2a3e263..a86443d 100644
--- a/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
+++ b/services/inputflinger/reader/mapper/TouchCursorInputMapperCommon.h
@@ -17,12 +17,13 @@
 #ifndef _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H
 #define _UI_INPUTREADER_TOUCH_CURSOR_INPUT_MAPPER_COMMON_H
 
+#include <input/DisplayViewport.h>
+#include <stdint.h>
+
 #include "EventHub.h"
 #include "InputListener.h"
 #include "InputReaderContext.h"
 
-#include <stdint.h>
-
 namespace android {
 
 // --- Static Definitions ---
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index 99a572a..10b6a18 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -765,7 +765,7 @@
             mPointerController = getContext()->getPointerController(getDeviceId());
         }
     } else {
-        mPointerController.clear();
+        mPointerController.reset();
     }
 
     if (viewportChanged || deviceModeChanged) {
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.h b/services/inputflinger/reader/mapper/TouchInputMapper.h
index 58bfc5c..7f811a0 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.h
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.h
@@ -376,7 +376,7 @@
     nsecs_t mDownTime;
 
     // The pointer controller, or null if the device is not a pointer.
-    sp<PointerControllerInterface> mPointerController;
+    std::shared_ptr<PointerControllerInterface> mPointerController;
 
     std::vector<VirtualKey> mVirtualKeys;
 
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 1a133dc..ea4d885 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -2368,7 +2368,7 @@
         mWindow =
                 new FakeWindowHandle(mApplication, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
         mWindow->setFrame(Rect(0, 0, 30, 30));
-        mWindow->setDispatchingTimeout(10ms);
+        mWindow->setDispatchingTimeout(30ms);
         mWindow->setFocus(true);
         // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
         // window.
@@ -2760,7 +2760,7 @@
 
         mFocusedWindow =
                 new FakeWindowHandle(mApplication, mDispatcher, "Focused", ADISPLAY_ID_DEFAULT);
-        mFocusedWindow->setDispatchingTimeout(10ms);
+        mFocusedWindow->setDispatchingTimeout(30ms);
         mFocusedWindow->setFrame(Rect(50, 50, 100, 100));
         mFocusedWindow->setLayoutParamFlags(InputWindowInfo::FLAG_NOT_TOUCH_MODAL |
                                             InputWindowInfo::FLAG_SPLIT_TOUCH);
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index c457a15..18bd3d0 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -27,12 +27,13 @@
 #include <TestInputListener.h>
 #include <TouchInputMapper.h>
 #include <UinputDevice.h>
-
 #include <android-base/thread_annotations.h>
 #include <gtest/gtest.h>
 #include <inttypes.h>
 #include <math.h>
 
+#include <memory>
+
 namespace android {
 
 using std::chrono_literals::operator""ms;
@@ -76,15 +77,14 @@
     int32_t mButtonState;
     int32_t mDisplayId;
 
-protected:
-    virtual ~FakePointerController() { }
-
 public:
     FakePointerController() :
         mHaveBounds(false), mMinX(0), mMinY(0), mMaxX(0), mMaxY(0), mX(0), mY(0),
         mButtonState(0), mDisplayId(ADISPLAY_ID_DEFAULT) {
     }
 
+    virtual ~FakePointerController() {}
+
     void setBounds(float minX, float minY, float maxX, float maxY) {
         mHaveBounds = true;
         mMinX = minX;
@@ -176,7 +176,7 @@
     std::condition_variable mDevicesChangedCondition;
 
     InputReaderConfiguration mConfig;
-    KeyedVector<int32_t, sp<FakePointerController> > mPointerControllers;
+    std::unordered_map<int32_t, std::shared_ptr<FakePointerController>> mPointerControllers;
     std::vector<InputDeviceInfo> mInputDevices GUARDED_BY(mLock);
     bool mInputDevicesChanged GUARDED_BY(mLock){false};
     std::vector<DisplayViewport> mViewports;
@@ -256,8 +256,8 @@
 
     void removeDisabledDevice(int32_t deviceId) { mConfig.disabledDevices.erase(deviceId); }
 
-    void setPointerController(int32_t deviceId, const sp<FakePointerController>& controller) {
-        mPointerControllers.add(deviceId, controller);
+    void setPointerController(int32_t deviceId, std::shared_ptr<FakePointerController> controller) {
+        mPointerControllers.insert_or_assign(deviceId, std::move(controller));
     }
 
     const InputReaderConfiguration* getReaderConfiguration() const {
@@ -318,8 +318,8 @@
         *outConfig = mConfig;
     }
 
-    virtual sp<PointerControllerInterface> obtainPointerController(int32_t deviceId) {
-        return mPointerControllers.valueFor(deviceId);
+    virtual std::shared_ptr<PointerControllerInterface> obtainPointerController(int32_t deviceId) {
+        return mPointerControllers[deviceId];
     }
 
     virtual void notifyInputDevicesChanged(const std::vector<InputDeviceInfo>& inputDevices) {
@@ -847,7 +847,7 @@
     bool mUpdateGlobalMetaStateWasCalled;
     int32_t mGeneration;
     int32_t mNextId;
-    wp<PointerControllerInterface> mPointerController;
+    std::weak_ptr<PointerControllerInterface> mPointerController;
 
 public:
     FakeInputReaderContext(std::shared_ptr<EventHubInterface> eventHub,
@@ -876,7 +876,7 @@
     }
 
     void updatePointerDisplay() {
-        sp<PointerControllerInterface> controller = mPointerController.promote();
+        std::shared_ptr<PointerControllerInterface> controller = mPointerController.lock();
         if (controller != nullptr) {
             InputReaderConfiguration config;
             mPolicy->getReaderConfiguration(&config);
@@ -913,8 +913,8 @@
 
     virtual bool shouldDropVirtualKey(nsecs_t, int32_t, int32_t) { return false; }
 
-    virtual sp<PointerControllerInterface> getPointerController(int32_t deviceId) {
-        sp<PointerControllerInterface> controller = mPointerController.promote();
+    virtual std::shared_ptr<PointerControllerInterface> getPointerController(int32_t deviceId) {
+        std::shared_ptr<PointerControllerInterface> controller = mPointerController.lock();
         if (controller == nullptr) {
             controller = mPolicy->obtainPointerController(deviceId);
             mPointerController = controller;
@@ -2348,9 +2348,9 @@
         ASSERT_NEAR(distance, coords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), EPSILON);
     }
 
-    static void assertPosition(const sp<FakePointerController>& controller, float x, float y) {
+    static void assertPosition(const FakePointerController& controller, float x, float y) {
         float actualX, actualY;
-        controller->getPosition(&actualX, &actualY);
+        controller.getPosition(&actualX, &actualY);
         ASSERT_NEAR(x, actualX, 1);
         ASSERT_NEAR(y, actualY, 1);
     }
@@ -3021,12 +3021,12 @@
 protected:
     static const int32_t TRACKBALL_MOVEMENT_THRESHOLD;
 
-    sp<FakePointerController> mFakePointerController;
+    std::shared_ptr<FakePointerController> mFakePointerController;
 
     virtual void SetUp() override {
         InputMapperTest::SetUp();
 
-        mFakePointerController = new FakePointerController();
+        mFakePointerController = std::make_shared<FakePointerController>();
         mFakePolicy->setPointerController(mDevice->getId(), mFakePointerController);
     }
 
@@ -3682,7 +3682,7 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
     ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
             110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
+    ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
 }
 
 TEST_F(CursorInputMapperTest, Process_PointerCapture) {
@@ -3710,7 +3710,7 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
     ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
             10.0f, 20.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 100.0f, 200.0f));
+    ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 100.0f, 200.0f));
 
     // Button press.
     process(mapper, ARBITRARY_TIME, EV_KEY, BTN_MOUSE, 1);
@@ -3749,7 +3749,7 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_MOVE, args.action);
     ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
             30.0f, 40.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 100.0f, 200.0f));
+    ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 100.0f, 200.0f));
 
     // Disable pointer capture and check that the device generation got bumped
     // and events are generated the usual way.
@@ -3770,7 +3770,7 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
     ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
             110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
+    ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
 }
 
 TEST_F(CursorInputMapperTest, Process_ShouldHandleDisplayId) {
@@ -3798,7 +3798,7 @@
     ASSERT_EQ(AMOTION_EVENT_ACTION_HOVER_MOVE, args.action);
     ASSERT_NO_FATAL_FAILURE(assertPointerCoords(args.pointerCoords[0],
             110.0f, 220.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f));
-    ASSERT_NO_FATAL_FAILURE(assertPosition(mFakePointerController, 110.0f, 220.0f));
+    ASSERT_NO_FATAL_FAILURE(assertPosition(*mFakePointerController, 110.0f, 220.0f));
     ASSERT_EQ(SECOND_DISPLAY_ID, args.displayId);
 }
 
@@ -6806,7 +6806,8 @@
 
 TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShouldHandleDisplayId) {
     // Setup for second display.
-    sp<FakePointerController> fakePointerController = new FakePointerController();
+    std::shared_ptr<FakePointerController> fakePointerController =
+            std::make_shared<FakePointerController>();
     fakePointerController->setBounds(0, 0, DISPLAY_WIDTH - 1, DISPLAY_HEIGHT - 1);
     fakePointerController->setPosition(100, 200);
     fakePointerController->setButtonState(0);
@@ -6866,7 +6867,8 @@
     device2->reset(ARBITRARY_TIME);
 
     // Setup PointerController.
-    sp<FakePointerController> fakePointerController = new FakePointerController();
+    std::shared_ptr<FakePointerController> fakePointerController =
+            std::make_shared<FakePointerController>();
     mFakePolicy->setPointerController(mDevice->getId(), fakePointerController);
     mFakePolicy->setPointerController(SECOND_DEVICE_ID, fakePointerController);
 
diff --git a/services/powermanager/PowerHalWrapper.cpp b/services/powermanager/PowerHalWrapper.cpp
index 5f4bfed..95f8623 100644
--- a/services/powermanager/PowerHalWrapper.cpp
+++ b/services/powermanager/PowerHalWrapper.cpp
@@ -117,8 +117,7 @@
         bool isSupported = false;
         auto isSupportedRet = mHandle->isBoostSupported(boost, &isSupported);
         if (!isSupportedRet.isOk()) {
-            ALOGV("Skipped setBoost %s because Power HAL is not available to check "
-                  "support",
+            ALOGV("Skipped setBoost %s because Power HAL is not available to check support",
                   toString(boost).c_str());
             return HalResult::FAILED;
         }
@@ -149,8 +148,7 @@
         bool isSupported = false;
         auto isSupportedRet = mHandle->isModeSupported(mode, &isSupported);
         if (!isSupportedRet.isOk()) {
-            ALOGV("Skipped setMode %s because Power HAL is not available to check "
-                  "support",
+            ALOGV("Skipped setMode %s because Power HAL is not available to check support",
                   toString(mode).c_str());
             return HalResult::FAILED;
         }
diff --git a/services/powermanager/benchmarks/Android.bp b/services/powermanager/benchmarks/Android.bp
new file mode 100644
index 0000000..5975269
--- /dev/null
+++ b/services/powermanager/benchmarks/Android.bp
@@ -0,0 +1,39 @@
+// Copyright (C) 2020 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_benchmark {
+    name: "libpowermanager_benchmarks",
+    srcs: [
+        "main.cpp",
+        "PowerHalAidlBenchmarks.cpp",
+        "PowerHalControllerBenchmarks.cpp",
+        "PowerHalHidlBenchmarks.cpp",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libhidlbase",
+        "liblog",
+        "libpowermanager",
+        "libutils",
+        "android.hardware.power@1.0",
+        "android.hardware.power@1.1",
+        "android.hardware.power-cpp",
+    ],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+}
diff --git a/services/powermanager/benchmarks/AndroidTest.xml b/services/powermanager/benchmarks/AndroidTest.xml
new file mode 100644
index 0000000..40f4872
--- /dev/null
+++ b/services/powermanager/benchmarks/AndroidTest.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2020 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.
+  -->
+<configuration description="Config for libpowermanager benchmarks">
+    <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+        <option name="cleanup" value="true" />
+        <option name="push" value="libpowermanager_benchmarks->/data/benchmarktest/benchmark" />
+    </target_preparer>
+    <option name="test-suite-tag" value="apct" />
+    <option name="test-suite-tag" value="apct-metric-instrumentation" />
+    <test class="com.android.tradefed.testtype.GoogleBenchmarkTest" >
+        <option name="native-benchmark-device-path" value="/data/benchmarktest" />
+        <option name="benchmark-module-name" value="benchmark" />
+    </test>
+</configuration>
diff --git a/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp
new file mode 100644
index 0000000..a6dad51
--- /dev/null
+++ b/services/powermanager/benchmarks/PowerHalAidlBenchmarks.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *            http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PowerHalAidlBenchmarks"
+
+#include <android/hardware/power/Boost.h>
+#include <android/hardware/power/IPower.h>
+#include <android/hardware/power/Mode.h>
+
+#include <benchmark/benchmark.h>
+
+#include <binder/IServiceManager.h>
+
+using android::hardware::power::Boost;
+using android::hardware::power::IPower;
+using android::hardware::power::Mode;
+
+using namespace android;
+
+template <class R, class... Args0, class... Args1>
+static void runBenchmark(benchmark::State& state, R (IPower::*fn)(Args0...), Args1&&... args1) {
+    sp<IPower> hal = waitForVintfService<IPower>();
+
+    if (hal == nullptr) {
+        ALOGI("Power HAL AIDL not available, skipping test...");
+        return;
+    }
+
+    while (state.KeepRunning()) {
+        (*hal.*fn)(std::forward<Args1>(args1)...);
+    }
+}
+
+static void BM_PowerHalAidlBenchmarks_isBoostSupported(benchmark::State& state) {
+    bool isSupported;
+    runBenchmark(state, &IPower::isBoostSupported, Boost::INTERACTION, &isSupported);
+}
+
+static void BM_PowerHalAidlBenchmarks_isModeSupported(benchmark::State& state) {
+    bool isSupported;
+    runBenchmark(state, &IPower::isModeSupported, Mode::INTERACTIVE, &isSupported);
+}
+
+static void BM_PowerHalAidlBenchmarks_setBoost(benchmark::State& state) {
+    runBenchmark(state, &IPower::setBoost, Boost::INTERACTION, 0);
+}
+
+static void BM_PowerHalAidlBenchmarks_setMode(benchmark::State& state) {
+    runBenchmark(state, &IPower::setMode, Mode::INTERACTIVE, false);
+}
+
+BENCHMARK(BM_PowerHalAidlBenchmarks_isBoostSupported);
+BENCHMARK(BM_PowerHalAidlBenchmarks_isModeSupported);
+BENCHMARK(BM_PowerHalAidlBenchmarks_setBoost);
+BENCHMARK(BM_PowerHalAidlBenchmarks_setMode);
diff --git a/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp
new file mode 100644
index 0000000..a3a1f4e
--- /dev/null
+++ b/services/powermanager/benchmarks/PowerHalControllerBenchmarks.cpp
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *            http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PowerHalControllerBenchmarks"
+
+#include <android/hardware/power/Boost.h>
+#include <android/hardware/power/Mode.h>
+
+#include <benchmark/benchmark.h>
+
+#include <powermanager/PowerHalController.h>
+
+using android::hardware::power::Boost;
+using android::hardware::power::Mode;
+using android::power::PowerHalController;
+
+using namespace android;
+
+static void BM_PowerHalControllerBenchmarks_init(benchmark::State& state) {
+    while (state.KeepRunning()) {
+        PowerHalController controller;
+        controller.init();
+    }
+}
+
+static void BM_PowerHalControllerBenchmarks_initCached(benchmark::State& state) {
+    PowerHalController controller;
+    // First connection out of test.
+    controller.init();
+
+    while (state.KeepRunning()) {
+        controller.init();
+    }
+}
+
+static void BM_PowerHalControllerBenchmarks_setBoost(benchmark::State& state) {
+    while (state.KeepRunning()) {
+        PowerHalController controller;
+        controller.setBoost(Boost::INTERACTION, 0);
+    }
+}
+
+static void BM_PowerHalControllerBenchmarks_setBoostCached(benchmark::State& state) {
+    PowerHalController controller;
+    // First call out of test, to cache supported boost.
+    controller.setBoost(Boost::INTERACTION, 0);
+
+    while (state.KeepRunning()) {
+        controller.setBoost(Boost::INTERACTION, 0);
+    }
+}
+
+static void BM_PowerHalControllerBenchmarks_setMode(benchmark::State& state) {
+    while (state.KeepRunning()) {
+        PowerHalController controller;
+        controller.setMode(Mode::INTERACTIVE, false);
+    }
+}
+
+static void BM_PowerHalControllerBenchmarks_setModeCached(benchmark::State& state) {
+    PowerHalController controller;
+    // First call out of test, to cache supported mode.
+    controller.setMode(Mode::INTERACTIVE, false);
+
+    while (state.KeepRunning()) {
+        controller.setMode(Mode::INTERACTIVE, false);
+    }
+}
+
+BENCHMARK(BM_PowerHalControllerBenchmarks_init);
+BENCHMARK(BM_PowerHalControllerBenchmarks_initCached);
+BENCHMARK(BM_PowerHalControllerBenchmarks_setBoost);
+BENCHMARK(BM_PowerHalControllerBenchmarks_setBoostCached);
+BENCHMARK(BM_PowerHalControllerBenchmarks_setMode);
+BENCHMARK(BM_PowerHalControllerBenchmarks_setModeCached);
diff --git a/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp b/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp
new file mode 100644
index 0000000..5542ac4
--- /dev/null
+++ b/services/powermanager/benchmarks/PowerHalHidlBenchmarks.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *            http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "PowerHalHidlBenchmarks"
+
+#include <android/hardware/power/1.1/IPower.h>
+#include <android/hardware/power/Boost.h>
+#include <android/hardware/power/IPower.h>
+#include <android/hardware/power/Mode.h>
+
+#include <benchmark/benchmark.h>
+
+#include <hardware/power.h>
+#include <hardware_legacy/power.h>
+
+using android::hardware::power::Boost;
+using android::hardware::power::Mode;
+using android::hardware::power::V1_0::Feature;
+using android::hardware::power::V1_0::PowerHint;
+using IPower1_0 = android::hardware::power::V1_0::IPower;
+using IPower1_1 = android::hardware::power::V1_1::IPower;
+
+using namespace android;
+
+template <class R, class I, class... Args0, class... Args1>
+static void runBenchmark(benchmark::State& state, R (I::*fn)(Args0...), Args1&&... args1) {
+    sp<I> hal = I::getService();
+
+    if (hal == nullptr) {
+        ALOGI("Power HAL HIDL not available, skipping test...");
+        return;
+    }
+
+    while (state.KeepRunning()) {
+        (*hal.*fn)(std::forward<Args1>(args1)...);
+    }
+}
+
+static void BM_PowerHalHidlBenchmarks_setFeature(benchmark::State& state) {
+    runBenchmark(state, &IPower1_0::setFeature, Feature::POWER_FEATURE_DOUBLE_TAP_TO_WAKE, false);
+}
+
+static void BM_PowerHalHidlBenchmarks_setInteractive(benchmark::State& state) {
+    runBenchmark(state, &IPower1_0::setInteractive, false);
+}
+
+static void BM_PowerHalHidlBenchmarks_powerHint(benchmark::State& state) {
+    runBenchmark(state, &IPower1_0::powerHint, PowerHint::INTERACTION, 0);
+}
+
+static void BM_PowerHalHidlBenchmarks_powerHintAsync(benchmark::State& state) {
+    runBenchmark(state, &IPower1_1::powerHintAsync, PowerHint::INTERACTION, 0);
+}
+
+BENCHMARK(BM_PowerHalHidlBenchmarks_setFeature);
+BENCHMARK(BM_PowerHalHidlBenchmarks_setInteractive);
+BENCHMARK(BM_PowerHalHidlBenchmarks_powerHint);
+BENCHMARK(BM_PowerHalHidlBenchmarks_powerHintAsync);
diff --git a/services/powermanager/benchmarks/main.cpp b/services/powermanager/benchmarks/main.cpp
new file mode 100644
index 0000000..15c57bf
--- /dev/null
+++ b/services/powermanager/benchmarks/main.cpp
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *            http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <benchmark/benchmark.h>
+
+BENCHMARK_MAIN();
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index a790d0b..804a3c3 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -145,6 +145,7 @@
         "DisplayHardware/HWComposer.cpp",
         "DisplayHardware/PowerAdvisor.cpp",
         "DisplayHardware/VirtualDisplaySurface.cpp",
+        "DisplayRenderArea.cpp",
         "Effects/Daltonizer.cpp",
         "EventLog/EventLog.cpp",
         "FrameTracer/FrameTracer.cpp",
@@ -152,6 +153,7 @@
         "Layer.cpp",
         "LayerProtoHelper.cpp",
         "LayerRejecter.cpp",
+        "LayerRenderArea.cpp",
         "LayerVector.cpp",
         "MonitoredProducer.cpp",
         "NativeWindowSurface.cpp",
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index 07be791..5f95182 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -208,8 +208,12 @@
 }
 
 bool BufferQueueLayer::latchSidebandStream(bool& recomputeVisibleRegions) {
+    // We need to update the sideband stream if the layer has both a buffer and a sideband stream.
+    const bool updateSidebandStream = hasFrameUpdate() && mSidebandStream.get();
+
     bool sidebandStreamChanged = true;
-    if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false)) {
+    if (mSidebandStreamChanged.compare_exchange_strong(sidebandStreamChanged, false) ||
+        updateSidebandStream) {
         // mSidebandStreamChanged was changed to false
         mSidebandStream = mConsumer->getSidebandStream();
         auto* layerCompositionState = editCompositionState();
diff --git a/services/surfaceflinger/DisplayDevice.h b/services/surfaceflinger/DisplayDevice.h
index 81b3ccf..576488c 100644
--- a/services/surfaceflinger/DisplayDevice.h
+++ b/services/surfaceflinger/DisplayDevice.h
@@ -40,7 +40,6 @@
 #include "DisplayHardware/DisplayIdentification.h"
 #include "DisplayHardware/Hal.h"
 #include "DisplayHardware/PowerAdvisor.h"
-#include "RenderArea.h"
 #include "Scheduler/HwcStrongTypes.h"
 
 namespace android {
@@ -246,123 +245,4 @@
     bool isPrimary{false};
 };
 
-class DisplayRenderArea : public RenderArea {
-public:
-    static std::unique_ptr<RenderArea> create(wp<const DisplayDevice> displayWeak,
-                                              const Rect& sourceCrop, ui::Size reqSize,
-                                              ui::Dataspace reqDataSpace, RotationFlags rotation,
-                                              bool allowSecureLayers = true) {
-        if (auto display = displayWeak.promote()) {
-            // Using new to access a private constructor.
-            return std::unique_ptr<DisplayRenderArea>(
-                    new DisplayRenderArea(std::move(display), sourceCrop, reqSize, reqDataSpace,
-                                          rotation, allowSecureLayers));
-        }
-        return nullptr;
-    }
-
-    const ui::Transform& getTransform() const override { return mTransform; }
-    Rect getBounds() const override { return mDisplay->getBounds(); }
-    int getHeight() const override { return mDisplay->getHeight(); }
-    int getWidth() const override { return mDisplay->getWidth(); }
-    bool isSecure() const override { return mAllowSecureLayers && mDisplay->isSecure(); }
-    sp<const DisplayDevice> getDisplayDevice() const override { return mDisplay; }
-
-    bool needsFiltering() const override {
-        // check if the projection from the logical render area
-        // to the physical render area requires filtering
-        const Rect& sourceCrop = getSourceCrop();
-        int width = sourceCrop.width();
-        int height = sourceCrop.height();
-        if (getRotationFlags() & ui::Transform::ROT_90) {
-            std::swap(width, height);
-        }
-        return width != getReqWidth() || height != getReqHeight();
-    }
-
-    Rect getSourceCrop() const override {
-        // use the projected display viewport by default.
-        if (mSourceCrop.isEmpty()) {
-            return mDisplay->getSourceClip();
-        }
-
-        // If there is a source crop provided then it is assumed that the device
-        // was in portrait orientation. This may not logically be true, so
-        // correct for the orientation error by undoing the rotation
-
-        ui::Rotation logicalOrientation = mDisplay->getOrientation();
-        if (logicalOrientation == ui::Rotation::Rotation90) {
-            logicalOrientation = ui::Rotation::Rotation270;
-        } else if (logicalOrientation == ui::Rotation::Rotation270) {
-            logicalOrientation = ui::Rotation::Rotation90;
-        }
-
-        const auto flags = ui::Transform::toRotationFlags(logicalOrientation);
-        int width = mDisplay->getSourceClip().getWidth();
-        int height = mDisplay->getSourceClip().getHeight();
-        ui::Transform rotation;
-        rotation.set(flags, width, height);
-        return rotation.transform(mSourceCrop);
-    }
-
-private:
-    DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop, ui::Size reqSize,
-                      ui::Dataspace reqDataSpace, RotationFlags rotation, bool allowSecureLayers)
-          : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, display->getViewport(),
-                       applyDeviceOrientation(rotation, display)),
-            mDisplay(std::move(display)),
-            mSourceCrop(sourceCrop),
-            mAllowSecureLayers(allowSecureLayers) {}
-
-    static RotationFlags applyDeviceOrientation(RotationFlags orientationFlag,
-                                                const sp<const DisplayDevice>& device) {
-        uint32_t inverseRotate90 = 0;
-        uint32_t inverseReflect = 0;
-
-        // Reverse the logical orientation.
-        ui::Rotation logicalOrientation = device->getOrientation();
-        if (logicalOrientation == ui::Rotation::Rotation90) {
-            logicalOrientation = ui::Rotation::Rotation270;
-        } else if (logicalOrientation == ui::Rotation::Rotation270) {
-            logicalOrientation = ui::Rotation::Rotation90;
-        }
-
-        const ui::Rotation orientation = device->getPhysicalOrientation() + logicalOrientation;
-
-        switch (orientation) {
-            case ui::ROTATION_0:
-                return orientationFlag;
-
-            case ui::ROTATION_90:
-                inverseRotate90 = ui::Transform::ROT_90;
-                inverseReflect = ui::Transform::ROT_180;
-                break;
-
-            case ui::ROTATION_180:
-                inverseReflect = ui::Transform::ROT_180;
-                break;
-
-            case ui::ROTATION_270:
-                inverseRotate90 = ui::Transform::ROT_90;
-                break;
-        }
-
-        const uint32_t rotate90 = orientationFlag & ui::Transform::ROT_90;
-        uint32_t reflect = orientationFlag & ui::Transform::ROT_180;
-
-        // Apply reflection for double rotation.
-        if (rotate90 & inverseRotate90) {
-            reflect = ~reflect & ui::Transform::ROT_180;
-        }
-
-        return static_cast<RotationFlags>((rotate90 ^ inverseRotate90) |
-                                          (reflect ^ inverseReflect));
-    }
-
-    const sp<const DisplayDevice> mDisplay;
-    const Rect mSourceCrop;
-    const bool mAllowSecureLayers;
-    const ui::Transform mTransform = ui::Transform();
-};
-
 } // namespace android
diff --git a/services/surfaceflinger/DisplayRenderArea.cpp b/services/surfaceflinger/DisplayRenderArea.cpp
new file mode 100644
index 0000000..7cd283d
--- /dev/null
+++ b/services/surfaceflinger/DisplayRenderArea.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "DisplayRenderArea.h"
+#include "DisplayDevice.h"
+
+namespace android {
+namespace {
+
+RenderArea::RotationFlags applyDeviceOrientation(RenderArea::RotationFlags rotation,
+                                                 const DisplayDevice& display) {
+    uint32_t inverseRotate90 = 0;
+    uint32_t inverseReflect = 0;
+
+    // Reverse the logical orientation.
+    ui::Rotation logicalOrientation = display.getOrientation();
+    if (logicalOrientation == ui::Rotation::Rotation90) {
+        logicalOrientation = ui::Rotation::Rotation270;
+    } else if (logicalOrientation == ui::Rotation::Rotation270) {
+        logicalOrientation = ui::Rotation::Rotation90;
+    }
+
+    const ui::Rotation orientation = display.getPhysicalOrientation() + logicalOrientation;
+
+    switch (orientation) {
+        case ui::ROTATION_0:
+            return rotation;
+
+        case ui::ROTATION_90:
+            inverseRotate90 = ui::Transform::ROT_90;
+            inverseReflect = ui::Transform::ROT_180;
+            break;
+
+        case ui::ROTATION_180:
+            inverseReflect = ui::Transform::ROT_180;
+            break;
+
+        case ui::ROTATION_270:
+            inverseRotate90 = ui::Transform::ROT_90;
+            break;
+    }
+
+    const uint32_t rotate90 = rotation & ui::Transform::ROT_90;
+    uint32_t reflect = rotation & ui::Transform::ROT_180;
+
+    // Apply reflection for double rotation.
+    if (rotate90 & inverseRotate90) {
+        reflect = ~reflect & ui::Transform::ROT_180;
+    }
+
+    return static_cast<RenderArea::RotationFlags>((rotate90 ^ inverseRotate90) |
+                                                  (reflect ^ inverseReflect));
+}
+
+} // namespace
+
+std::unique_ptr<RenderArea> DisplayRenderArea::create(wp<const DisplayDevice> displayWeak,
+                                                      const Rect& sourceCrop, ui::Size reqSize,
+                                                      ui::Dataspace reqDataSpace,
+                                                      RotationFlags rotation,
+                                                      bool allowSecureLayers) {
+    if (auto display = displayWeak.promote()) {
+        // Using new to access a private constructor.
+        return std::unique_ptr<DisplayRenderArea>(
+                new DisplayRenderArea(std::move(display), sourceCrop, reqSize, reqDataSpace,
+                                      rotation, allowSecureLayers));
+    }
+    return nullptr;
+}
+
+DisplayRenderArea::DisplayRenderArea(sp<const DisplayDevice> display, const Rect& sourceCrop,
+                                     ui::Size reqSize, ui::Dataspace reqDataSpace,
+                                     RotationFlags rotation, bool allowSecureLayers)
+      : RenderArea(reqSize, CaptureFill::OPAQUE, reqDataSpace, display->getViewport(),
+                   applyDeviceOrientation(rotation, *display)),
+        mDisplay(std::move(display)),
+        mSourceCrop(sourceCrop),
+        mAllowSecureLayers(allowSecureLayers) {}
+
+const ui::Transform& DisplayRenderArea::getTransform() const {
+    return mTransform;
+}
+
+Rect DisplayRenderArea::getBounds() const {
+    return mDisplay->getBounds();
+}
+
+int DisplayRenderArea::getHeight() const {
+    return mDisplay->getHeight();
+}
+
+int DisplayRenderArea::getWidth() const {
+    return mDisplay->getWidth();
+}
+
+bool DisplayRenderArea::isSecure() const {
+    return mAllowSecureLayers && mDisplay->isSecure();
+}
+
+sp<const DisplayDevice> DisplayRenderArea::getDisplayDevice() const {
+    return mDisplay;
+}
+
+bool DisplayRenderArea::needsFiltering() const {
+    // check if the projection from the logical render area
+    // to the physical render area requires filtering
+    const Rect& sourceCrop = getSourceCrop();
+    int width = sourceCrop.width();
+    int height = sourceCrop.height();
+    if (getRotationFlags() & ui::Transform::ROT_90) {
+        std::swap(width, height);
+    }
+    return width != getReqWidth() || height != getReqHeight();
+}
+
+Rect DisplayRenderArea::getSourceCrop() const {
+    // use the projected display viewport by default.
+    if (mSourceCrop.isEmpty()) {
+        return mDisplay->getSourceClip();
+    }
+
+    // If there is a source crop provided then it is assumed that the device
+    // was in portrait orientation. This may not logically be true, so
+    // correct for the orientation error by undoing the rotation
+
+    ui::Rotation logicalOrientation = mDisplay->getOrientation();
+    if (logicalOrientation == ui::Rotation::Rotation90) {
+        logicalOrientation = ui::Rotation::Rotation270;
+    } else if (logicalOrientation == ui::Rotation::Rotation270) {
+        logicalOrientation = ui::Rotation::Rotation90;
+    }
+
+    const auto flags = ui::Transform::toRotationFlags(logicalOrientation);
+    int width = mDisplay->getSourceClip().getWidth();
+    int height = mDisplay->getSourceClip().getHeight();
+    ui::Transform rotation;
+    rotation.set(flags, width, height);
+    return rotation.transform(mSourceCrop);
+}
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/DisplayRenderArea.h b/services/surfaceflinger/DisplayRenderArea.h
new file mode 100644
index 0000000..340efb5
--- /dev/null
+++ b/services/surfaceflinger/DisplayRenderArea.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2020 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 <ui/GraphicTypes.h>
+#include <ui/Transform.h>
+
+#include "RenderArea.h"
+
+namespace android {
+
+class DisplayDevice;
+
+class DisplayRenderArea : public RenderArea {
+public:
+    static std::unique_ptr<RenderArea> create(wp<const DisplayDevice>, const Rect& sourceCrop,
+                                              ui::Size reqSize, ui::Dataspace,
+                                              RotationFlags rotation,
+                                              bool allowSecureLayers = true);
+
+    const ui::Transform& getTransform() const override;
+    Rect getBounds() const override;
+    int getHeight() const override;
+    int getWidth() const override;
+    bool isSecure() const override;
+    sp<const DisplayDevice> getDisplayDevice() const override;
+    bool needsFiltering() const override;
+    Rect getSourceCrop() const override;
+
+private:
+    DisplayRenderArea(sp<const DisplayDevice>, const Rect& sourceCrop, ui::Size reqSize,
+                      ui::Dataspace, RotationFlags rotation, bool allowSecureLayers = true);
+
+    const sp<const DisplayDevice> mDisplay;
+    const Rect mSourceCrop;
+    const bool mAllowSecureLayers;
+    const ui::Transform mTransform;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index f36b67d..a34af17 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1325,6 +1325,10 @@
     return Layer::PRIORITY_UNSET;
 }
 
+bool Layer::isLayerFocusedBasedOnPriority(int32_t priority) {
+    return priority == PRIORITY_FOCUSED_WITH_MODE || priority == PRIORITY_FOCUSED_WITHOUT_MODE;
+};
+
 uint32_t Layer::getLayerStack() const {
     auto p = mDrawingParent.promote();
     if (p == nullptr) {
@@ -1558,7 +1562,7 @@
     result.append("-------------------------------");
     result.append("-------------------------------");
     result.append("-------------------------------");
-    result.append("---------\n");
+    result.append("-------------------\n");
     result.append(" Layer name\n");
     result.append("           Z | ");
     result.append(" Window Type | ");
@@ -1566,12 +1570,12 @@
     result.append(" Transform | ");
     result.append("  Disp Frame (LTRB) | ");
     result.append("         Source Crop (LTRB) | ");
-    result.append("    Frame Rate (Explicit)\n");
+    result.append("    Frame Rate (Explicit) [Focused]\n");
     result.append("-------------------------------");
     result.append("-------------------------------");
     result.append("-------------------------------");
     result.append("-------------------------------");
-    result.append("---------\n");
+    result.append("-------------------\n");
 }
 
 std::string Layer::frameRateCompatibilityString(Layer::FrameRateCompatibility compatibility) {
@@ -1622,17 +1626,20 @@
                   crop.bottom);
     if (layerState.frameRate.rate != 0 ||
         layerState.frameRate.type != FrameRateCompatibility::Default) {
-        StringAppendF(&result, "% 6.2ffps %15s\n", layerState.frameRate.rate,
+        StringAppendF(&result, "% 6.2ffps %15s", layerState.frameRate.rate,
                       frameRateCompatibilityString(layerState.frameRate.type).c_str());
     } else {
-        StringAppendF(&result, "\n");
+        StringAppendF(&result, "                         ");
     }
 
+    const auto focused = isLayerFocusedBasedOnPriority(getFrameRateSelectionPriority());
+    StringAppendF(&result, "    [%s]\n", focused ? "*" : " ");
+
     result.append("- - - - - - - - - - - - - - - - ");
     result.append("- - - - - - - - - - - - - - - - ");
     result.append("- - - - - - - - - - - - - - - - ");
     result.append("- - - - - - - - - - - - - - - - ");
-    result.append("- - -\n");
+    result.append("- - - - - - - -\n");
 }
 
 void Layer::dumpFrameStats(std::string& result) const {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 068424b..2c90c92 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -94,7 +94,16 @@
 
 class Layer : public virtual RefBase, compositionengine::LayerFE {
     static std::atomic<int32_t> sSequence;
+    // The following constants represent priority of the window. SF uses this information when
+    // deciding which window has a priority when deciding about the refresh rate of the screen.
+    // Priority 0 is considered the highest priority. -1 means that the priority is unset.
     static constexpr int32_t PRIORITY_UNSET = -1;
+    // Windows that are in focus and voted for the preferred mode ID
+    static constexpr int32_t PRIORITY_FOCUSED_WITH_MODE = 0;
+    // // Windows that are in focus, but have not requested a specific mode ID.
+    static constexpr int32_t PRIORITY_FOCUSED_WITHOUT_MODE = 1;
+    // Windows that are not in focus, but voted for a specific mode ID.
+    static constexpr int32_t PRIORITY_NOT_FOCUSED_WITH_MODE = 2;
 
 public:
     mutable bool contentDirty{false};
@@ -400,6 +409,7 @@
     //  If the variable is not set on the layer, it traverses up the tree to inherit the frame
     //  rate priority from its parent.
     virtual int32_t getFrameRateSelectionPriority() const;
+    static bool isLayerFocusedBasedOnPriority(int32_t priority);
 
     virtual ui::Dataspace getDataSpace() const { return ui::Dataspace::UNKNOWN; }
 
diff --git a/services/surfaceflinger/LayerRenderArea.cpp b/services/surfaceflinger/LayerRenderArea.cpp
new file mode 100644
index 0000000..c4f8666
--- /dev/null
+++ b/services/surfaceflinger/LayerRenderArea.cpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ui/GraphicTypes.h>
+#include <ui/Transform.h>
+
+#include "ContainerLayer.h"
+#include "DisplayDevice.h"
+#include "Layer.h"
+#include "LayerRenderArea.h"
+#include "SurfaceFlinger.h"
+
+namespace android {
+namespace {
+
+struct ReparentForDrawing {
+    const sp<Layer>& oldParent;
+
+    ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent,
+                       const Rect& drawingBounds)
+          : oldParent(oldParent) {
+        // Compute and cache the bounds for the new parent layer.
+        newParent->computeBounds(drawingBounds.toFloatRect(), ui::Transform(),
+                                 0.f /* shadowRadius */);
+        oldParent->setChildrenDrawingParent(newParent);
+    }
+    ~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); }
+};
+
+} // namespace
+
+LayerRenderArea::LayerRenderArea(SurfaceFlinger& flinger, sp<Layer> layer, const Rect& crop,
+                                 ui::Size reqSize, ui::Dataspace reqDataSpace, bool childrenOnly,
+                                 const Rect& displayViewport)
+      : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, displayViewport),
+        mLayer(std::move(layer)),
+        mCrop(crop),
+        mFlinger(flinger),
+        mChildrenOnly(childrenOnly) {}
+
+const ui::Transform& LayerRenderArea::getTransform() const {
+    return mTransform;
+}
+
+Rect LayerRenderArea::getBounds() const {
+    return mLayer->getBufferSize(mLayer->getDrawingState());
+}
+
+int LayerRenderArea::getHeight() const {
+    return mLayer->getBufferSize(mLayer->getDrawingState()).getHeight();
+}
+
+int LayerRenderArea::getWidth() const {
+    return mLayer->getBufferSize(mLayer->getDrawingState()).getWidth();
+}
+
+bool LayerRenderArea::isSecure() const {
+    return false;
+}
+
+bool LayerRenderArea::needsFiltering() const {
+    return mNeedsFiltering;
+}
+
+sp<const DisplayDevice> LayerRenderArea::getDisplayDevice() const {
+    return nullptr;
+}
+
+Rect LayerRenderArea::getSourceCrop() const {
+    if (mCrop.isEmpty()) {
+        return getBounds();
+    } else {
+        return mCrop;
+    }
+}
+
+void LayerRenderArea::render(std::function<void()> drawLayers) {
+    using namespace std::string_literals;
+
+    const Rect sourceCrop = getSourceCrop();
+    // no need to check rotation because there is none
+    mNeedsFiltering = sourceCrop.width() != getReqWidth() || sourceCrop.height() != getReqHeight();
+
+    if (!mChildrenOnly) {
+        mTransform = mLayer->getTransform().inverse();
+        drawLayers();
+    } else {
+        uint32_t w = static_cast<uint32_t>(getWidth());
+        uint32_t h = static_cast<uint32_t>(getHeight());
+        // In the "childrenOnly" case we reparent the children to a screenshot
+        // layer which has no properties set and which does not draw.
+        sp<ContainerLayer> screenshotParentLayer = mFlinger.getFactory().createContainerLayer(
+                {&mFlinger, nullptr, "Screenshot Parent"s, w, h, 0, LayerMetadata()});
+
+        ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop);
+        drawLayers();
+    }
+}
+
+} // namespace android
diff --git a/services/surfaceflinger/LayerRenderArea.h b/services/surfaceflinger/LayerRenderArea.h
new file mode 100644
index 0000000..81690b9
--- /dev/null
+++ b/services/surfaceflinger/LayerRenderArea.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2020 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 <string>
+
+#include <ui/GraphicTypes.h>
+#include <ui/Transform.h>
+#include <utils/StrongPointer.h>
+
+#include "RenderArea.h"
+
+namespace android {
+
+class DisplayDevice;
+class Layer;
+class SurfaceFlinger;
+
+class LayerRenderArea : public RenderArea {
+public:
+    LayerRenderArea(SurfaceFlinger& flinger, sp<Layer> layer, const Rect& crop, ui::Size reqSize,
+                    ui::Dataspace reqDataSpace, bool childrenOnly, const Rect& displayViewport);
+
+    const ui::Transform& getTransform() const override;
+    Rect getBounds() const override;
+    int getHeight() const override;
+    int getWidth() const override;
+    bool isSecure() const override;
+    bool needsFiltering() const override;
+    sp<const DisplayDevice> getDisplayDevice() const override;
+    Rect getSourceCrop() const override;
+
+    void render(std::function<void()> drawLayers) override;
+
+private:
+    const sp<Layer> mLayer;
+    const Rect mCrop;
+
+    ui::Transform mTransform;
+    bool mNeedsFiltering = false;
+
+    SurfaceFlinger& mFlinger;
+    const bool mChildrenOnly;
+};
+
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/RegionSamplingThread.cpp b/services/surfaceflinger/RegionSamplingThread.cpp
index 398fd40..899d1fa 100644
--- a/services/surfaceflinger/RegionSamplingThread.cpp
+++ b/services/surfaceflinger/RegionSamplingThread.cpp
@@ -35,6 +35,7 @@
 #include <string>
 
 #include "DisplayDevice.h"
+#include "DisplayRenderArea.h"
 #include "Layer.h"
 #include "Promise.h"
 #include "Scheduler/DispSync.h"
@@ -383,8 +384,9 @@
     const Rect sampledBounds = sampleRegion.bounds();
 
     SurfaceFlinger::RenderAreaFuture renderAreaFuture = promise::defer([=] {
-        return DisplayRenderArea::create(displayWeak, sampledBounds, sampledBounds.getSize(),
-                                         ui::Dataspace::V0_SRGB, orientation);
+        return DisplayRenderArea::create(displayWeak, screencapRegion.bounds(),
+                                         sampledBounds.getSize(), ui::Dataspace::V0_SRGB,
+                                         orientation);
     });
 
     std::unordered_set<sp<IRegionSamplingListener>, SpHash<IRegionSamplingListener>> listeners;
diff --git a/services/surfaceflinger/Scheduler/LayerHistory.cpp b/services/surfaceflinger/Scheduler/LayerHistory.cpp
index 2925109..ecf2597 100644
--- a/services/surfaceflinger/Scheduler/LayerHistory.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistory.cpp
@@ -109,6 +109,8 @@
         auto layer = weakLayer.promote();
         // Only use the layer if the reference still exists.
         if (layer || CC_UNLIKELY(mTraceEnabled)) {
+            const auto layerFocused =
+                    Layer::isLayerFocusedBasedOnPriority(layer->getFrameRateSelectionPriority());
             // Check if frame rate was set on layer.
             const auto frameRate = layer->getFrameRateForLayerTree();
             if (frameRate.rate > 0.f) {
@@ -122,11 +124,12 @@
                             return LayerVoteType::NoVote;
                     }
                 }();
-                summary.push_back({layer->getName(), voteType, frameRate.rate, /* weight */ 1.0f});
+                summary.push_back({layer->getName(), voteType, frameRate.rate, /* weight */ 1.0f,
+                                   layerFocused});
             } else if (recent) {
                 summary.push_back({layer->getName(), LayerVoteType::Heuristic,
                                    info->getRefreshRate(now),
-                                   /* weight */ 1.0f});
+                                   /* weight */ 1.0f, layerFocused});
             }
 
             if (CC_UNLIKELY(mTraceEnabled)) {
diff --git a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
index ee612b0..aa04bd7 100644
--- a/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
+++ b/services/surfaceflinger/Scheduler/LayerHistoryV2.cpp
@@ -125,9 +125,10 @@
             continue;
         }
 
-        // TODO(b/144307188): This needs to be plugged into layer summary as
-        //  an additional parameter.
-        ALOGV("Layer has priority: %d", strong->getFrameRateSelectionPriority());
+        const auto frameRateSelectionPriority = strong->getFrameRateSelectionPriority();
+        const auto layerFocused = Layer::isLayerFocusedBasedOnPriority(frameRateSelectionPriority);
+        ALOGV("%s has priority: %d %s focused", strong->getName().c_str(),
+              frameRateSelectionPriority, layerFocused ? "" : "not");
 
         const auto [type, refreshRate] = info->getRefreshRate(now);
         // Skip NoVote layer as those don't have any requirements
@@ -143,7 +144,7 @@
 
         const float layerArea = transformed.getWidth() * transformed.getHeight();
         float weight = mDisplayArea ? layerArea / mDisplayArea : 0.0f;
-        summary.push_back({strong->getName(), type, refreshRate, weight});
+        summary.push_back({strong->getName(), type, refreshRate, weight, layerFocused});
 
         if (CC_UNLIKELY(mTraceEnabled)) {
             trace(layer, *info, type, static_cast<int>(std::round(refreshRate)));
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index a6036c6..053d0a7 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -212,10 +212,11 @@
             bool inPrimaryRange =
                     scores[i].first->inPolicy(policy->primaryRange.min, policy->primaryRange.max);
             if ((primaryRangeIsSingleRate || !inPrimaryRange) &&
-                layer.vote != LayerVoteType::ExplicitDefault &&
-                layer.vote != LayerVoteType::ExplicitExactOrMultiple) {
-                // Only layers with explicit frame rate settings are allowed to score refresh rates
-                // outside the primary range.
+                !(layer.focused &&
+                  (layer.vote == LayerVoteType::ExplicitDefault ||
+                   layer.vote == LayerVoteType::ExplicitExactOrMultiple))) {
+                // Only focused layers with explicit frame rate settings are allowed to score
+                // refresh rates outside the primary range.
                 continue;
             }
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 8a51b85..27bf0ec 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -195,15 +195,22 @@
     // Captures the layer requirements for a refresh rate. This will be used to determine the
     // display refresh rate.
     struct LayerRequirement {
-        std::string name;         // Layer's name. Used for debugging purposes.
-        LayerVoteType vote;       // Layer vote type.
-        float desiredRefreshRate; // Layer's desired refresh rate, if applicable.
-        float weight; // Layer's weight in the range of [0, 1]. The higher the weight the more
-                      // impact this layer would have on choosing the refresh rate.
+        // Layer's name. Used for debugging purposes.
+        std::string name;
+        // Layer vote type.
+        LayerVoteType vote = LayerVoteType::NoVote;
+        // Layer's desired refresh rate, if applicable.
+        float desiredRefreshRate = 0.0f;
+        // Layer's weight in the range of [0, 1]. The higher the weight the more impact this layer
+        // would have on choosing the refresh rate.
+        float weight = 0.0f;
+        // Whether layer is in focus or not based on WindowManager's state
+        bool focused = false;
 
         bool operator==(const LayerRequirement& other) const {
             return name == other.name && vote == other.vote &&
-                    desiredRefreshRate == other.desiredRefreshRate && weight == other.weight;
+                    desiredRefreshRate == other.desiredRefreshRate && weight == other.weight &&
+                    focused == other.focused;
         }
 
         bool operator!=(const LayerRequirement& other) const { return !(*this == other); }
diff --git a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
index a3cb772..ab5773d 100644
--- a/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
+++ b/services/surfaceflinger/Scheduler/VSyncPredictor.cpp
@@ -77,7 +77,14 @@
     std::lock_guard<std::mutex> lk(mMutex);
 
     if (!validate(timestamp)) {
-        ALOGV("timestamp was too far off the last known timestamp");
+        // VSR could elect to ignore the incongruent timestamp or resetModel(). If ts is ignored,
+        // don't insert this ts into mTimestamps ringbuffer.
+        if (!mTimestamps.empty()) {
+            mKnownTimestamp =
+                    std::max(timestamp, *std::max_element(mTimestamps.begin(), mTimestamps.end()));
+        } else {
+            mKnownTimestamp = timestamp;
+        }
         return false;
     }
 
@@ -236,7 +243,13 @@
 
 void VSyncPredictor::clearTimestamps() {
     if (!mTimestamps.empty()) {
-        mKnownTimestamp = *std::max_element(mTimestamps.begin(), mTimestamps.end());
+        auto const maxRb = *std::max_element(mTimestamps.begin(), mTimestamps.end());
+        if (mKnownTimestamp) {
+            mKnownTimestamp = std::max(*mKnownTimestamp, maxRb);
+        } else {
+            mKnownTimestamp = maxRb;
+        }
+
         mTimestamps.clear();
         mLastTimestampIndex = 0;
     }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e68c484..db6f1ad 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -102,10 +102,12 @@
 #include "DisplayHardware/FramebufferSurface.h"
 #include "DisplayHardware/HWComposer.h"
 #include "DisplayHardware/VirtualDisplaySurface.h"
+#include "DisplayRenderArea.h"
 #include "EffectLayer.h"
 #include "Effects/Daltonizer.h"
 #include "FrameTracer/FrameTracer.h"
 #include "Layer.h"
+#include "LayerRenderArea.h"
 #include "LayerVector.h"
 #include "MonitoredProducer.h"
 #include "NativeWindowSurface.h"
@@ -2003,7 +2005,8 @@
 
     bool runHandleTransaction =
             (transactionFlags && (transactionFlags != eTransactionFlushNeeded)) ||
-            flushedATransaction;
+            flushedATransaction ||
+            mForceTraversal;
 
     if (runHandleTransaction) {
         handleTransaction(eTransactionMask);
@@ -5559,86 +5562,6 @@
         float frameScale, bool childrenOnly) {
     ATRACE_CALL();
 
-    class LayerRenderArea : public RenderArea {
-    public:
-        LayerRenderArea(SurfaceFlinger* flinger, const sp<Layer>& layer, const Rect crop,
-                        ui::Size reqSize, Dataspace reqDataSpace, bool childrenOnly,
-                        const Rect& displayViewport)
-              : RenderArea(reqSize, CaptureFill::CLEAR, reqDataSpace, displayViewport),
-                mLayer(layer),
-                mCrop(crop),
-                mNeedsFiltering(false),
-                mFlinger(flinger),
-                mChildrenOnly(childrenOnly) {}
-        const ui::Transform& getTransform() const override { return mTransform; }
-        Rect getBounds() const override { return mLayer->getBufferSize(mLayer->getDrawingState()); }
-        int getHeight() const override {
-            return mLayer->getBufferSize(mLayer->getDrawingState()).getHeight();
-        }
-        int getWidth() const override {
-            return mLayer->getBufferSize(mLayer->getDrawingState()).getWidth();
-        }
-        bool isSecure() const override { return false; }
-        bool needsFiltering() const override { return mNeedsFiltering; }
-        sp<const DisplayDevice> getDisplayDevice() const override { return nullptr; }
-        Rect getSourceCrop() const override {
-            if (mCrop.isEmpty()) {
-                return getBounds();
-            } else {
-                return mCrop;
-            }
-        }
-        class ReparentForDrawing {
-        public:
-            const sp<Layer>& oldParent;
-            const sp<Layer>& newParent;
-
-            ReparentForDrawing(const sp<Layer>& oldParent, const sp<Layer>& newParent,
-                               const Rect& drawingBounds)
-                  : oldParent(oldParent), newParent(newParent) {
-                // Compute and cache the bounds for the new parent layer.
-                newParent->computeBounds(drawingBounds.toFloatRect(), ui::Transform(),
-                                         0.f /* shadowRadius */);
-                oldParent->setChildrenDrawingParent(newParent);
-            }
-            ~ReparentForDrawing() { oldParent->setChildrenDrawingParent(oldParent); }
-        };
-
-        void render(std::function<void()> drawLayers) override {
-            const Rect sourceCrop = getSourceCrop();
-            // no need to check rotation because there is none
-            mNeedsFiltering = sourceCrop.width() != getReqWidth() ||
-                sourceCrop.height() != getReqHeight();
-
-            if (!mChildrenOnly) {
-                mTransform = mLayer->getTransform().inverse();
-                drawLayers();
-            } else {
-                uint32_t w = static_cast<uint32_t>(getWidth());
-                uint32_t h = static_cast<uint32_t>(getHeight());
-                // In the "childrenOnly" case we reparent the children to a screenshot
-                // layer which has no properties set and which does not draw.
-                sp<ContainerLayer> screenshotParentLayer =
-                        mFlinger->getFactory().createContainerLayer({mFlinger, nullptr,
-                                                                     "Screenshot Parent"s, w, h, 0,
-                                                                     LayerMetadata()});
-
-                ReparentForDrawing reparent(mLayer, screenshotParentLayer, sourceCrop);
-                drawLayers();
-            }
-        }
-
-    private:
-        const sp<Layer> mLayer;
-        const Rect mCrop;
-
-        ui::Transform mTransform;
-        bool mNeedsFiltering;
-
-        SurfaceFlinger* mFlinger;
-        const bool mChildrenOnly;
-    };
-
     ui::Size reqSize;
     sp<Layer> parent;
     Rect crop(sourceCrop);
@@ -5705,7 +5628,7 @@
     }
 
     RenderAreaFuture renderAreaFuture = promise::defer([=]() -> std::unique_ptr<RenderArea> {
-        return std::make_unique<LayerRenderArea>(this, parent, crop, reqSize, reqDataspace,
+        return std::make_unique<LayerRenderArea>(*this, parent, crop, reqSize, reqDataspace,
                                                  childrenOnly, displayViewport);
     });
 
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6a3937f..e9a2905 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -95,6 +95,7 @@
 class MessageBase;
 class RefreshRateOverlay;
 class RegionSamplingThread;
+class RenderArea;
 class TimeStats;
 class FrameTracer;
 
diff --git a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
index cfc301b..7b1f0fb 100644
--- a/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
+++ b/services/surfaceflinger/sysprop/SurfaceFlingerProperties.sysprop
@@ -328,7 +328,7 @@
 prop {
     api_name: "refresh_rate_switching"
     type: Boolean
-    scope: System
+    scope: Public
     access: Readonly
     prop_name: "ro.surface_flinger.refresh_rate_switching"
     deprecated: true
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 456891e..9355e61 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -35,6 +35,7 @@
 #include <utils/String8.h>
 
 #include "BufferQueueLayer.h"
+#include "DisplayRenderArea.h"
 #include "EffectLayer.h"
 #include "Layer.h"
 #include "TestableSurfaceFlinger.h"
@@ -248,8 +249,9 @@
 
     int fd = -1;
     status_t result =
-            mFlinger.captureScreenImplLocked(*renderArea, traverseLayers, mCaptureScreenBuffer.get(),
-                                             useIdentityTransform, forSystem, &fd, regionSampling);
+            mFlinger.captureScreenImplLocked(*renderArea, traverseLayers,
+                                             mCaptureScreenBuffer.get(), useIdentityTransform,
+                                             forSystem, &fd, regionSampling);
     if (fd >= 0) {
         close(fd);
     }
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index fed591c..03d4460 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -292,7 +292,8 @@
                                                  /*currentConfigId=*/HWC_CONFIG_ID_60);
 
     const auto makeLayerRequirements = [](float refreshRate) -> std::vector<LayerRequirement> {
-        return {{"testLayer", LayerVoteType::Heuristic, refreshRate, 1.0f}};
+        return {{"testLayer", LayerVoteType::Heuristic, refreshRate, /*weight*/ 1.0f,
+                 /*focused*/ false}};
     };
 
     EXPECT_EQ(mExpected90Config,
@@ -1132,6 +1133,7 @@
     lr.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr.desiredRefreshRate = 60.0f;
     lr.name = "60Hz ExplicitExactOrMultiple";
+    lr.focused = true;
     EXPECT_EQ(mExpected60Config,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = true},
                                                      &consideredSignals));
@@ -1140,6 +1142,7 @@
     lr.vote = LayerVoteType::ExplicitDefault;
     lr.desiredRefreshRate = 60.0f;
     lr.name = "60Hz ExplicitDefault";
+    lr.focused = true;
     EXPECT_EQ(mExpected60Config,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = true, .idle = true},
                                                      &consideredSignals));
@@ -1162,18 +1165,20 @@
     lr.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr.desiredRefreshRate = 90.0f;
     lr.name = "90Hz ExplicitExactOrMultiple";
+    lr.focused = true;
     EXPECT_EQ(mExpected90Config,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = true}));
 
     lr.vote = LayerVoteType::ExplicitDefault;
     lr.desiredRefreshRate = 90.0f;
     lr.name = "90Hz ExplicitDefault";
+    lr.focused = true;
     EXPECT_EQ(mExpected90Config,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = true}));
 }
 
 TEST_F(RefreshRateConfigsTest,
-       getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitLayers) {
+       getBestRefreshRate_withDisplayManagerRequestingSingleRate_onlySwitchesRatesForExplicitFocusedLayers) {
     auto refreshRateConfigs =
             std::make_unique<RefreshRateConfigs>(m60_90Device,
                                                  /*currentConfigId=*/HWC_CONFIG_ID_90);
@@ -1194,30 +1199,55 @@
     lr.vote = LayerVoteType::ExplicitExactOrMultiple;
     lr.desiredRefreshRate = 60.0f;
     lr.name = "60Hz ExplicitExactOrMultiple";
+    lr.focused = false;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.focused = true;
     EXPECT_EQ(mExpected60Config,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
 
     lr.vote = LayerVoteType::ExplicitDefault;
     lr.desiredRefreshRate = 60.0f;
     lr.name = "60Hz ExplicitDefault";
+    lr.focused = false;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.focused = true;
     EXPECT_EQ(mExpected60Config,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
 
     lr.vote = LayerVoteType::Heuristic;
     lr.desiredRefreshRate = 60.0f;
     lr.name = "60Hz Heuristic";
+    lr.focused = false;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.focused = true;
     EXPECT_EQ(mExpected90Config,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
 
     lr.vote = LayerVoteType::Max;
     lr.desiredRefreshRate = 60.0f;
     lr.name = "60Hz Max";
+    lr.focused = false;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.focused = true;
     EXPECT_EQ(mExpected90Config,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
 
     lr.vote = LayerVoteType::Min;
     lr.desiredRefreshRate = 60.0f;
     lr.name = "60Hz Min";
+    lr.focused = false;
+    EXPECT_EQ(mExpected90Config,
+              refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
+
+    lr.focused = true;
     EXPECT_EQ(mExpected90Config,
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
 }
@@ -1256,10 +1286,11 @@
 
     // Return the config ID from calling getBestRefreshRate() for a single layer with the
     // given voteType and fps.
-    auto getFrameRate = [&](LayerVoteType voteType, float fps,
-                            bool touchActive = false) -> HwcConfigIndexType {
+    auto getFrameRate = [&](LayerVoteType voteType, float fps, bool touchActive = false,
+                            bool focused = true) -> HwcConfigIndexType {
         layers[0].vote = voteType;
         layers[0].desiredRefreshRate = fps;
+        layers[0].focused = focused;
         return refreshRateConfigs->getBestRefreshRate(layers, {.touch = touchActive, .idle = false})
                 .getConfigId();
     };
@@ -1277,6 +1308,14 @@
     EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitDefault, 90.f));
     EXPECT_EQ(HWC_CONFIG_ID_90, getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f));
 
+    // Layers not focused are not allowed to override primary config
+    EXPECT_EQ(HWC_CONFIG_ID_60,
+              getFrameRate(LayerVoteType::ExplicitDefault, 90.f, /*touch=*/false,
+                           /*focused=*/false));
+    EXPECT_EQ(HWC_CONFIG_ID_60,
+              getFrameRate(LayerVoteType::ExplicitExactOrMultiple, 90.f, /*touch=*/false,
+                           /*focused=*/false));
+
     // Touch boost should be restricted to the primary range.
     EXPECT_EQ(HWC_CONFIG_ID_60, getFrameRate(LayerVoteType::Max, 90.f, /*touch=*/true));
     // When we're higher than the primary range max due to a layer frame rate setting, touch boost
diff --git a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
index bf2a889..fc39235 100644
--- a/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
+++ b/services/surfaceflinger/tests/unittests/VSyncPredictorTest.cpp
@@ -124,6 +124,38 @@
     EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + changedPeriod));
 }
 
+// b/159882858
+TEST_F(VSyncPredictorTest, updatesTimebaseForSyntheticAfterIdleTime) {
+    for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+        EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += mPeriod));
+    }
+
+    EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
+
+    auto const halfPeriod = mPeriod >> 2;
+    nsecs_t relativelyLongGapWithDrift = mPeriod * 100 + halfPeriod;
+
+    EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += relativelyLongGapWithDrift));
+
+    tracker.resetModel();
+    EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
+}
+
+TEST_F(VSyncPredictorTest, uponBadVsyncWillSwitchToSyntheticWhileRecalibrating) {
+    auto const slightlyMorePeriod = mPeriod + 10;
+    for (auto i = 0u; i < kMinimumSamplesForPrediction; i++) {
+        EXPECT_TRUE(tracker.addVsyncTimestamp(mNow += slightlyMorePeriod));
+    }
+
+    EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + slightlyMorePeriod));
+
+    auto const halfPeriod = mPeriod >> 2;
+    EXPECT_FALSE(tracker.addVsyncTimestamp(mNow += halfPeriod));
+
+    tracker.resetModel();
+    EXPECT_THAT(tracker.nextAnticipatedVSyncTimeFrom(mNow), Eq(mNow + mPeriod));
+}
+
 TEST_F(VSyncPredictorTest, adaptsToFenceTimelines_60hzHighVariance) {
     // these are precomputed simulated 16.6s vsyncs with uniform distribution +/- 1.6ms error
     std::vector<nsecs_t> const simulatedVsyncs{