Merge "SF: RefreshRateOverlay: Create buffers on demand"
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index cbb74b3..afa0b4d 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2864,31 +2864,23 @@
     // duration is logged into MYLOG instead.
     PrintHeader();
 
-    // TODO(b/158737089) reduce code repetition in if branches
-    if (options_->telephony_only) {
-        MaybeTakeEarlyScreenshot();
-        onUiIntensiveBugreportDumpsFinished(calling_uid);
-        MaybeCheckUserConsent(calling_uid, calling_package);
-        DumpstateTelephonyOnly(calling_package);
-    } else if (options_->wifi_only) {
-        MaybeTakeEarlyScreenshot();
-        onUiIntensiveBugreportDumpsFinished(calling_uid);
-        MaybeCheckUserConsent(calling_uid, calling_package);
-        DumpstateWifiOnly();
-    } else if (options_->limited_only) {
-        MaybeTakeEarlyScreenshot();
-        onUiIntensiveBugreportDumpsFinished(calling_uid);
-        MaybeCheckUserConsent(calling_uid, calling_package);
-        DumpstateLimitedOnly();
-    } else {
+    bool is_dumpstate_restricted = options_->telephony_only
+                                   || options_->wifi_only
+                                   || options_->limited_only;
+    if (!is_dumpstate_restricted) {
         // Invoke critical dumpsys first to preserve system state, before doing anything else.
         RunDumpsysCritical();
-
-        // Take screenshot and get consent only after critical dumpsys has finished.
-        MaybeTakeEarlyScreenshot();
-        onUiIntensiveBugreportDumpsFinished(calling_uid);
-        MaybeCheckUserConsent(calling_uid, calling_package);
-
+    }
+    MaybeTakeEarlyScreenshot();
+    onUiIntensiveBugreportDumpsFinished(calling_uid);
+    MaybeCheckUserConsent(calling_uid, calling_package);
+    if (options_->telephony_only) {
+        DumpstateTelephonyOnly(calling_package);
+    } else if (options_->wifi_only) {
+        DumpstateWifiOnly();
+    } else if (options_->limited_only) {
+        DumpstateLimitedOnly();
+    } else {
         // Dump state for the default case. This also drops root.
         RunStatus s = DumpstateDefaultAfterCritical();
         if (s != RunStatus::OK) {
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index b821578..818804a 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -398,6 +398,10 @@
         PLOG(ERROR) << "Failed to prepare " << profile_dir;
         return false;
     }
+    if (selinux_android_restorecon(profile_dir.c_str(), 0)) {
+        PLOG(ERROR) << "Failed to restorecon " << profile_dir;
+        return false;
+    }
 
     const std::string ref_profile_path =
             create_primary_reference_profile_package_dir_path(packageName);
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 594880a..65fc46e 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1818,10 +1818,13 @@
 
     pid_t pid = fork();
     if (pid == 0) {
+        // Need to set schedpolicy before dropping privileges
+        // for cgroup migration. See details at b/175178520.
+        SetDex2OatScheduling(boot_complete);
+
         /* child -- drop privileges before continuing */
         drop_capabilities(uid);
 
-        SetDex2OatScheduling(boot_complete);
         if (flock(out_oat.fd(), LOCK_EX | LOCK_NB) != 0) {
             PLOG(ERROR) << "flock(" << out_oat.path() << ") failed";
             _exit(DexoptReturnCodes::kFlock);
diff --git a/cmds/lshal/Android.bp b/cmds/lshal/Android.bp
index 1994e56..0cbb80f 100644
--- a/cmds/lshal/Android.bp
+++ b/cmds/lshal/Android.bp
@@ -16,6 +16,7 @@
     name: "liblshal",
     shared_libs: [
         "libbase",
+        "libbinderdebug",
         "libcutils",
         "libutils",
         "libhidlbase",
@@ -47,6 +48,7 @@
     name: "lshal_defaults",
     shared_libs: [
         "libbase",
+        "libbinderdebug",
         "libcutils",
         "libutils",
         "libhidlbase",
diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp
index 92958d9..22268ac 100644
--- a/cmds/lshal/ListCommand.cpp
+++ b/cmds/lshal/ListCommand.cpp
@@ -29,7 +29,6 @@
 
 #include <android-base/file.h>
 #include <android-base/logging.h>
-#include <android-base/parseint.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
 #include <hidl-hash/Hash.h>
 #include <hidl-util/FQName.h>
@@ -203,97 +202,14 @@
             lshal::getVintfInfo(getFrameworkMatrix(), fqInstance, ta, FRAMEWORK_MATRIX);
 }
 
-static bool scanBinderContext(pid_t pid,
-        const std::string &contextName,
-        std::function<void(const std::string&)> eachLine) {
-    std::ifstream ifs("/dev/binderfs/binder_logs/proc/" + std::to_string(pid));
-    if (!ifs.is_open()) {
-        ifs.open("/d/binder/proc/" + std::to_string(pid));
-        if (!ifs.is_open()) {
-            return false;
-        }
-    }
-
-    static const std::regex kContextLine("^context (\\w+)$");
-
-    bool isDesiredContext = false;
-    std::string line;
-    std::smatch match;
-    while(getline(ifs, line)) {
-        if (std::regex_search(line, match, kContextLine)) {
-            isDesiredContext = match.str(1) == contextName;
-            continue;
-        }
-
-        if (!isDesiredContext) {
-            continue;
-        }
-
-        eachLine(line);
-    }
-    return true;
-}
-
 bool ListCommand::getPidInfo(
-        pid_t serverPid, PidInfo *pidInfo) const {
-    static const std::regex kReferencePrefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
-    static const std::regex kThreadPrefix("^\\s*thread \\d+:\\s+l\\s+(\\d)(\\d)");
-
-    std::smatch match;
-    return scanBinderContext(serverPid, "hwbinder", [&](const std::string& line) {
-        if (std::regex_search(line, match, kReferencePrefix)) {
-            const std::string &ptrString = "0x" + match.str(2); // use number after c
-            uint64_t ptr;
-            if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
-                // Should not reach here, but just be tolerant.
-                err() << "Could not parse number " << ptrString << std::endl;
-                return;
-            }
-            const std::string proc = " proc ";
-            auto pos = line.rfind(proc);
-            if (pos != std::string::npos) {
-                for (const std::string &pidStr : split(line.substr(pos + proc.size()), ' ')) {
-                    int32_t pid;
-                    if (!::android::base::ParseInt(pidStr, &pid)) {
-                        err() << "Could not parse number " << pidStr << std::endl;
-                        return;
-                    }
-                    pidInfo->refPids[ptr].push_back(pid);
-                }
-            }
-
-            return;
-        }
-
-        if (std::regex_search(line, match, kThreadPrefix)) {
-            // "1" is waiting in binder driver
-            // "2" is poll. It's impossible to tell if these are in use.
-            //     and HIDL default code doesn't use it.
-            bool isInUse = match.str(1) != "1";
-            // "0" is a thread that has called into binder
-            // "1" is looper thread
-            // "2" is main looper thread
-            bool isHwbinderThread = match.str(2) != "0";
-
-            if (!isHwbinderThread) {
-                return;
-            }
-
-            if (isInUse) {
-                pidInfo->threadUsage++;
-            }
-
-            pidInfo->threadCount++;
-            return;
-        }
-
-        // not reference or thread line
-        return;
-    });
+        pid_t serverPid, BinderPidInfo *pidInfo) const {
+    const auto& status = getBinderPidInfo(BinderDebugContext::HWBINDER, serverPid, pidInfo);
+    return status == OK;
 }
 
-const PidInfo* ListCommand::getPidInfoCached(pid_t serverPid) {
-    auto pair = mCachedPidInfos.insert({serverPid, PidInfo{}});
+const BinderPidInfo* ListCommand::getPidInfoCached(pid_t serverPid) {
+    auto pair = mCachedPidInfos.insert({serverPid, BinderPidInfo{}});
     if (pair.second /* did insertion take place? */) {
         if (!getPidInfo(serverPid, &pair.first->second)) {
             return nullptr;
@@ -727,7 +643,7 @@
         entry->arch = fromBaseArchitecture(debugInfo.arch);
 
         if (debugInfo.pid != NO_PID) {
-            const PidInfo* pidInfo = getPidInfoCached(debugInfo.pid);
+            const BinderPidInfo* pidInfo = getPidInfoCached(debugInfo.pid);
             if (pidInfo == nullptr) {
                 handleError(IO_ERROR,
                             "no information for PID " + std::to_string(debugInfo.pid) +
diff --git a/cmds/lshal/ListCommand.h b/cmds/lshal/ListCommand.h
index 412aadd..561f9cb 100644
--- a/cmds/lshal/ListCommand.h
+++ b/cmds/lshal/ListCommand.h
@@ -25,6 +25,7 @@
 
 #include <android-base/macros.h>
 #include <android/hidl/manager/1.0/IServiceManager.h>
+#include <binderdebug/BinderDebug.h>
 #include <hidl-util/FqInstance.h>
 #include <vintf/HalManifest.h>
 #include <vintf/VintfObject.h>
@@ -40,12 +41,6 @@
 
 class Lshal;
 
-struct PidInfo {
-    std::map<uint64_t, Pids> refPids; // pids that are referenced
-    uint32_t threadUsage; // number of threads in use
-    uint32_t threadCount; // number of threads total
-};
-
 enum class HalType {
     BINDERIZED_SERVICES = 0,
     PASSTHROUGH_CLIENTS,
@@ -110,9 +105,9 @@
     // Get relevant information for a PID by parsing files under
     // /dev/binderfs/binder_logs or /d/binder.
     // It is a virtual member function so that it can be mocked.
-    virtual bool getPidInfo(pid_t serverPid, PidInfo *info) const;
+    virtual bool getPidInfo(pid_t serverPid, BinderPidInfo *info) const;
     // Retrieve from mCachedPidInfos and call getPidInfo if necessary.
-    const PidInfo* getPidInfoCached(pid_t serverPid);
+    const BinderPidInfo* getPidInfoCached(pid_t serverPid);
 
     void dumpTable(const NullableOStream<std::ostream>& out) const;
     void dumpVintf(const NullableOStream<std::ostream>& out) const;
@@ -191,7 +186,7 @@
     std::map<pid_t, std::string> mCmdlines;
 
     // Cache for getPidInfo.
-    std::map<pid_t, PidInfo> mCachedPidInfos;
+    std::map<pid_t, BinderPidInfo> mCachedPidInfos;
 
     // Cache for getPartition.
     std::map<pid_t, Partition> mPartitions;
diff --git a/cmds/lshal/TableEntry.h b/cmds/lshal/TableEntry.h
index 3c36813..476aa04 100644
--- a/cmds/lshal/TableEntry.h
+++ b/cmds/lshal/TableEntry.h
@@ -32,7 +32,7 @@
 namespace lshal {
 
 using android::procpartition::Partition;
-using Pids = std::vector<int32_t>;
+using Pids = std::vector<pid_t>;
 
 enum class TableColumnType : unsigned int {
     INTERFACE_NAME = 0,
diff --git a/cmds/lshal/test.cpp b/cmds/lshal/test.cpp
index ba6cdf1..b6ff28d 100644
--- a/cmds/lshal/test.cpp
+++ b/cmds/lshal/test.cpp
@@ -233,12 +233,12 @@
         return ListCommand::dumpVintf(out);
     }
     void internalPostprocess() { ListCommand::postprocess(); }
-    const PidInfo* getPidInfoCached(pid_t serverPid) {
+    const BinderPidInfo* getPidInfoCached(pid_t serverPid) {
         return ListCommand::getPidInfoCached(serverPid);
     }
 
     MOCK_METHOD0(postprocess, void());
-    MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, PidInfo*));
+    MOCK_CONST_METHOD2(getPidInfo, bool(pid_t, BinderPidInfo*));
     MOCK_CONST_METHOD1(parseCmdline, std::string(pid_t));
     MOCK_METHOD1(getPartition, Partition(pid_t));
 
@@ -299,8 +299,8 @@
 static std::vector<pid_t> getClients(pid_t serverId) {
     return {serverId + 1, serverId + 3};
 }
-static PidInfo getPidInfoFromId(pid_t serverId) {
-    PidInfo info;
+static BinderPidInfo getPidInfoFromId(pid_t serverId) {
+    BinderPidInfo info;
     info.refPids[getPtr(serverId)] = getClients(serverId);
     info.threadUsage = 10 + serverId;
     info.threadCount = 20 + serverId;
@@ -363,7 +363,7 @@
     void initMockList() {
         mockList = std::make_unique<NiceMock<MockListCommand>>(lshal.get());
         ON_CALL(*mockList, getPidInfo(_,_)).WillByDefault(Invoke(
-            [](pid_t serverPid, PidInfo* info) {
+            [](pid_t serverPid, BinderPidInfo* info) {
                 *info = getPidInfoFromId(serverPid);
                 return true;
             }));
diff --git a/data/etc/android.software.opengles.deqp.level-2020-03-01.xml b/data/etc/android.software.opengles.deqp.level-2020-03-01.xml
new file mode 100644
index 0000000..f11e0bb
--- /dev/null
+++ b/data/etc/android.software.opengles.deqp.level-2020-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard feature indicating that the device passes OpenGL ES
+     dEQP tests associated with date 2020-03-01 (0x07E40301). -->
+<permissions>
+    <feature name="android.software.opengles.deqp.level" version="132383489" />
+</permissions>
diff --git a/data/etc/android.software.opengles.deqp.level-2021-03-01.xml b/data/etc/android.software.opengles.deqp.level-2021-03-01.xml
new file mode 100644
index 0000000..b60697d
--- /dev/null
+++ b/data/etc/android.software.opengles.deqp.level-2021-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard feature indicating that the device passes OpenGL ES
+     dEQP tests associated with date 2021-03-01 (0x07E50301). -->
+<permissions>
+    <feature name="android.software.opengles.deqp.level" version="132449025" />
+</permissions>
diff --git a/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml
index 9c67d4a..d3ad45a 100644
--- a/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml
+++ b/data/etc/android.software.vulkan.deqp.level-2019-03-01.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<!-- This is the standard feature indicating that the device passes Vulkan deQP
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
      tests associated with date 2019-03-01 (0x07E30301). -->
 <permissions>
     <feature name="android.software.vulkan.deqp.level" version="132317953" />
diff --git a/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml
index 19b269b..84ba389 100644
--- a/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml
+++ b/data/etc/android.software.vulkan.deqp.level-2020-03-01.xml
@@ -14,7 +14,7 @@
      limitations under the License.
 -->
 
-<!-- This is the standard feature indicating that the device passes Vulkan deQP
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
      tests associated with date 2020-03-01 (0x07E40301). -->
 <permissions>
     <feature name="android.software.vulkan.deqp.level" version="132383489" />
diff --git a/data/etc/android.software.vulkan.deqp.level-2021-03-01.xml b/data/etc/android.software.vulkan.deqp.level-2021-03-01.xml
new file mode 100644
index 0000000..ae26269
--- /dev/null
+++ b/data/etc/android.software.vulkan.deqp.level-2021-03-01.xml
@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!-- This is the standard feature indicating that the device passes Vulkan dEQP
+     tests associated with date 2021-03-01 (0x07E50301). -->
+<permissions>
+    <feature name="android.software.vulkan.deqp.level" version="132449025" />
+</permissions>
diff --git a/data/etc/cec_config.xml b/data/etc/cec_config.xml
deleted file mode 100644
index 480e0ec..0000000
--- a/data/etc/cec_config.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
-<cec-settings>
-  <setting name="hdmi_cec_enabled"
-           value-type="int"
-           user-configurable="true">
-    <allowed-values>
-      <value int-value="0" />
-      <value int-value="1" />
-    </allowed-values>
-    <default-value int-value="1" />
-  </setting>
-  <setting name="hdmi_cec_version"
-           value-type="int"
-           user-configurable="true">
-    <allowed-values>
-      <value int-value="0x05" />
-      <value int-value="0x06" />
-    </allowed-values>
-    <default-value int-value="0x05" />
-  </setting>
-  <setting name="send_standby_on_sleep"
-           value-type="string"
-           user-configurable="true">
-    <allowed-values>
-      <value string-value="to_tv" />
-      <value string-value="broadcast" />
-      <value string-value="none" />
-    </allowed-values>
-    <default-value string-value="to_tv" />
-  </setting>
-  <setting name="power_state_change_on_active_source_lost"
-           value-type="string"
-           user-configurable="true">
-    <allowed-values>
-      <value string-value="none" />
-      <value string-value="standby_now" />
-    </allowed-values>
-    <default-value string-value="none" />
-  </setting>
-  <setting name="system_audio_mode_muting"
-           value-type="int"
-           user-configurable="true">
-    <allowed-values>
-      <value int-value="0" />
-      <value int-value="1" />
-    </allowed-values>
-    <default-value int-value="1" />
-  </setting>
-</cec-settings>
diff --git a/data/etc/pc_core_hardware.xml b/data/etc/pc_core_hardware.xml
new file mode 100644
index 0000000..c62da0a
--- /dev/null
+++ b/data/etc/pc_core_hardware.xml
@@ -0,0 +1,63 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<!-- These are the hardware components that all handheld devices
+     must include. Devices with optional hardware must also include extra
+     hardware files, per the comments below.
+
+     Handheld devices include phones, mobile Internet devices (MIDs),
+     Personal Media Players (PMPs), small tablets (7" or less), and similar
+     devices.
+-->
+<permissions>
+    <!-- This is Android and fully CTS compatible.  Basically this is for CTS tests to use. -->
+    <feature name="android.software.cts" />
+
+    <feature name="android.hardware.audio.output" />
+    <feature name="android.hardware.bluetooth" />
+    <feature name="android.hardware.microphone" />
+    <feature name="android.hardware.screen.portrait" />
+    <feature name="android.hardware.screen.landscape" />
+    <feature name="android.hardware.location" />
+    <feature name="android.hardware.location.network" />
+
+    <!-- basic system services -->
+    <feature name="android.software.app_widgets" />
+    <feature name="android.software.voice_recognizers" />
+    <feature name="android.software.backup" />
+    <feature name="android.software.home_screen" />
+    <feature name="android.software.input_methods" />
+    <feature name="android.software.picture_in_picture" />
+    <feature name="android.software.activities_on_secondary_displays" />
+    <feature name="android.software.print" />
+    <feature name="android.software.companion_device_setup" />
+    <feature name="android.software.autofill" />
+    <feature name="android.software.cant_save_state" />
+    <feature name="android.software.secure_lock_screen" />
+
+    <!-- Feature to specify if the device supports adding device admins. -->
+    <feature name="android.software.device_admin" />
+
+    <!-- Feature to specify if the device support managed users. -->
+    <feature name="android.software.managed_users" />
+
+    <!-- Feature to specify if the device supports controls. -->
+    <feature name="android.software.controls" />
+
+    <!-- Feature to specify if the device supports freeform. -->
+    <feature name="android.software.freeform_window_management" />
+    <feature name="android.hardware.type.pc" />
+</permissions>
\ No newline at end of file
diff --git a/include/audiomanager/AudioManager.h b/include/audiomanager/AudioManager.h
index 639df7a..4aa2f60 100644
--- a/include/audiomanager/AudioManager.h
+++ b/include/audiomanager/AudioManager.h
@@ -37,6 +37,7 @@
     PLAYER_STATE_STARTED  = 2,
     PLAYER_STATE_PAUSED   = 3,
     PLAYER_STATE_STOPPED  = 4,
+    PLAYER_UPDATE_DEVICE_ID = 5,
 } player_state_t;
 
 // must be kept in sync with definitions in AudioManager.java
diff --git a/include/audiomanager/IAudioManager.h b/include/audiomanager/IAudioManager.h
index 2f5ccb8..7d1f38f 100644
--- a/include/audiomanager/IAudioManager.h
+++ b/include/audiomanager/IAudioManager.h
@@ -49,7 +49,8 @@
                 audio_content_type_t content, const sp<IBinder>& player) = 0;
     /*oneway*/ virtual status_t playerAttributes(audio_unique_id_t piid, audio_usage_t usage,
                 audio_content_type_t content)= 0;
-    /*oneway*/ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event) = 0;
+    /*oneway*/ virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event,
+                audio_port_handle_t deviceId) = 0;
     /*oneway*/ virtual status_t releasePlayer(audio_unique_id_t piid) = 0;
     virtual audio_unique_id_t trackRecorder(const sp<IBinder>& recorder) = 0;
     /*oneway*/ virtual status_t recorderEvent(audio_unique_id_t riid, recorder_state_t event) = 0;
diff --git a/include/input/DisplayViewport.h b/include/input/DisplayViewport.h
index b90d57e..5e40ca7 100644
--- a/include/input/DisplayViewport.h
+++ b/include/input/DisplayViewport.h
@@ -119,7 +119,7 @@
         physicalBottom = height;
         deviceWidth = width;
         deviceHeight = height;
-        isActive = false;
+        isActive = true;
         uniqueId.clear();
         physicalPort = std::nullopt;
         type = ViewportType::INTERNAL;
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 90feedd..feaea63 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -83,9 +83,6 @@
     // or dessert updates. Instead, apex users should use libbinder_ndk.
     apex_available: [
         "//apex_available:platform",
-        // TODO(b/166468760) remove these three
-        "com.android.media.swcodec",
-        "test_com.android.media.swcodec",
     ],
 
     srcs: [
@@ -183,6 +180,14 @@
     ],
     tidy_checks_as_errors: [
         "*",
+        "-clang-analyzer-core.CallAndMessage",
+        "-clang-analyzer-core.uninitialized.Assign",
+        "-clang-analyzer-unix.Malloc,",
+        "-clang-analyzer-deadcode.DeadStores",
+        "-clang-analyzer-optin.cplusplus.UninitializedObject",
+        "-misc-no-recursion",
+        "-misc-redundant-expression",
+        "-misc-unused-using-decls",
     ],
 }
 
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index d4c7acf..7d01e0b 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -1248,10 +1248,22 @@
                 constexpr uint32_t kForwardReplyFlags = TF_CLEAR_BUF;
                 sendReply(reply, (tr.flags & kForwardReplyFlags));
             } else {
-                if (error != OK || reply.dataSize() != 0) {
-                    alog << "oneway function results will be dropped but finished with status "
-                         << statusToString(error)
-                         << " and parcel size " << reply.dataSize() << endl;
+                if (error != OK) {
+                    alog << "oneway function results for code " << tr.code
+                         << " on binder at "
+                         << reinterpret_cast<void*>(tr.target.ptr)
+                         << " will be dropped but finished with status "
+                         << statusToString(error);
+
+                    // ideally we could log this even when error == OK, but it
+                    // causes too much logspam because some manually-written
+                    // interfaces have clients that call methods which always
+                    // write results, sometimes as oneway methods.
+                    if (reply.dataSize() != 0) {
+                         alog << " and reply parcel size " << reply.dataSize();
+                    }
+
+                    alog << endl;
                 }
                 LOG_ONEWAY("NOT sending reply to %d!", mCallingPid);
             }
diff --git a/libs/binder/include/binder/AppOpsManager.h b/libs/binder/include/binder/AppOpsManager.h
index 35c697e..f1085cf 100644
--- a/libs/binder/include/binder/AppOpsManager.h
+++ b/libs/binder/include/binder/AppOpsManager.h
@@ -136,7 +136,9 @@
         OP_PHONE_CALL_MICROPHONE = 100,
         OP_PHONE_CALL_CAMERA = 101,
         OP_RECORD_AUDIO_HOTWORD = 102,
-        _NUM_OP = 103
+        // Ops 103-105 are currently unused in native, and intentionally omitted
+        OP_RECORD_AUDIO_OUTPUT = 106,
+        _NUM_OP = 107
     };
 
     AppOpsManager();
diff --git a/libs/binder/ndk/Android.bp b/libs/binder/ndk/Android.bp
index a57beee..bdb74dc 100644
--- a/libs/binder/ndk/Android.bp
+++ b/libs/binder/ndk/Android.bp
@@ -105,6 +105,14 @@
     ],
     tidy_checks_as_errors: [
         "*",
+        "-clang-analyzer-core.CallAndMessage",
+        "-clang-analyzer-core.uninitialized.Assign",
+        "-clang-analyzer-unix.Malloc,",
+        "-clang-analyzer-deadcode.DeadStores",
+        "-clang-analyzer-optin.cplusplus.UninitializedObject",
+        "-misc-no-recursion",
+        "-misc-redundant-expression",
+        "-misc-unused-using-decls",
     ],
 }
 
diff --git a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
index 2d85f90..04167f7 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -114,6 +114,13 @@
      */
     AIBinder** getR() { return &mBinder; }
 
+    bool operator!=(const SpAIBinder& rhs) const { return get() != rhs.get(); }
+    bool operator<(const SpAIBinder& rhs) const { return get() < rhs.get(); }
+    bool operator<=(const SpAIBinder& rhs) const { return get() <= rhs.get(); }
+    bool operator==(const SpAIBinder& rhs) const { return get() == rhs.get(); }
+    bool operator>(const SpAIBinder& rhs) const { return get() > rhs.get(); }
+    bool operator>=(const SpAIBinder& rhs) const { return get() >= rhs.get(); }
+
    private:
     AIBinder* mBinder = nullptr;
 };
@@ -200,6 +207,13 @@
     ~ScopedAParcel() {}
     ScopedAParcel(ScopedAParcel&&) = default;
     ScopedAParcel& operator=(ScopedAParcel&&) = default;
+
+    bool operator!=(const ScopedAParcel& rhs) const { return get() != rhs.get(); }
+    bool operator<(const ScopedAParcel& rhs) const { return get() < rhs.get(); }
+    bool operator<=(const ScopedAParcel& rhs) const { return get() <= rhs.get(); }
+    bool operator==(const ScopedAParcel& rhs) const { return get() == rhs.get(); }
+    bool operator>(const ScopedAParcel& rhs) const { return get() > rhs.get(); }
+    bool operator>=(const ScopedAParcel& rhs) const { return get() >= rhs.get(); }
 };
 
 /**
@@ -323,6 +337,13 @@
     ~ScopedFileDescriptor() {}
     ScopedFileDescriptor(ScopedFileDescriptor&&) = default;
     ScopedFileDescriptor& operator=(ScopedFileDescriptor&&) = default;
+
+    bool operator!=(const ScopedFileDescriptor& rhs) const { return get() != rhs.get(); }
+    bool operator<(const ScopedFileDescriptor& rhs) const { return get() < rhs.get(); }
+    bool operator<=(const ScopedFileDescriptor& rhs) const { return get() <= rhs.get(); }
+    bool operator==(const ScopedFileDescriptor& rhs) const { return get() == rhs.get(); }
+    bool operator>(const ScopedFileDescriptor& rhs) const { return get() > rhs.get(); }
+    bool operator>=(const ScopedFileDescriptor& rhs) const { return get() >= rhs.get(); }
 };
 
 }  // namespace ndk
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
index 4858514..cf2b9e9 100644
--- a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -114,6 +114,25 @@
 
     void reset() { AParcel_reset(mParcel.get()); }
 
+    inline bool operator!=(const AParcelableHolder& rhs) const {
+        return std::tie(mParcel, mStability) != std::tie(rhs.mParcel, rhs.mStability);
+    }
+    inline bool operator<(const AParcelableHolder& rhs) const {
+        return std::tie(mParcel, mStability) < std::tie(rhs.mParcel, rhs.mStability);
+    }
+    inline bool operator<=(const AParcelableHolder& rhs) const {
+        return std::tie(mParcel, mStability) <= std::tie(rhs.mParcel, rhs.mStability);
+    }
+    inline bool operator==(const AParcelableHolder& rhs) const {
+        return std::tie(mParcel, mStability) == std::tie(rhs.mParcel, rhs.mStability);
+    }
+    inline bool operator>(const AParcelableHolder& rhs) const {
+        return std::tie(mParcel, mStability) > std::tie(rhs.mParcel, rhs.mStability);
+    }
+    inline bool operator>=(const AParcelableHolder& rhs) const {
+        return std::tie(mParcel, mStability) >= std::tie(rhs.mParcel, rhs.mStability);
+    }
+
    private:
     mutable ndk::ScopedAParcel mParcel;
     parcelable_stability_t mStability;
diff --git a/libs/binder/parcel_fuzzer/main.cpp b/libs/binder/parcel_fuzzer/main.cpp
index 386c70b..78606cc 100644
--- a/libs/binder/parcel_fuzzer/main.cpp
+++ b/libs/binder/parcel_fuzzer/main.cpp
@@ -20,12 +20,16 @@
 #include "hwbinder.h"
 #include "util.h"
 
+#include <iostream>
+
 #include <android-base/logging.h>
 #include <fuzzbinder/random_parcel.h>
 #include <fuzzer/FuzzedDataProvider.h>
 
 #include <cstdlib>
 #include <ctime>
+#include <sys/resource.h>
+#include <sys/time.h>
 
 using android::fillRandomParcel;
 
@@ -77,7 +81,25 @@
     }
 }
 
+size_t getHardMemoryLimit() {
+    struct rlimit limit;
+    CHECK(0 == getrlimit(RLIMIT_AS, &limit)) << errno;
+    return limit.rlim_max;
+}
+
+void setMemoryLimit(size_t cur, size_t max) {
+    const struct rlimit kLimit = {
+       .rlim_cur = cur,
+       .rlim_max = max,
+    };
+    CHECK(0 == setrlimit(RLIMIT_AS, &kLimit)) << errno;
+}
+
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+    static constexpr size_t kMemLimit = 1 * 1024 * 1024;
+    size_t hardLimit = getHardMemoryLimit();
+    setMemoryLimit(std::min(kMemLimit, hardLimit), hardLimit);
+
     if (size <= 1) return 0;  // no use
 
     // avoid timeouts, see b/142617274, b/142473153
@@ -102,5 +124,7 @@
 
     provider.PickValueInArray(fuzzBackend)(std::move(provider));
 
+    setMemoryLimit(hardLimit, hardLimit);
+
     return 0;
 }
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index 0f7d159..a5261e5 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -404,6 +404,13 @@
     EXPECT_EQ(NO_ERROR, ret);
 }
 
+TEST_F(BinderLibTest, NopTransactionOneway) {
+    status_t ret;
+    Parcel data, reply;
+    ret = m_server->transact(BINDER_LIB_TEST_NOP_TRANSACTION, data, &reply, TF_ONE_WAY);
+    EXPECT_EQ(NO_ERROR, ret);
+}
+
 TEST_F(BinderLibTest, NopTransactionClear) {
     status_t ret;
     Parcel data, reply;
@@ -1182,9 +1189,6 @@
         virtual status_t onTransact(uint32_t code,
                                     const Parcel& data, Parcel* reply,
                                     uint32_t flags = 0) {
-            //printf("%s: code %d\n", __func__, code);
-            (void)flags;
-
             if (getuid() != (uid_t)IPCThreadState::self()->getCallingUid()) {
                 return PERMISSION_DENIED;
             }
@@ -1258,8 +1262,12 @@
                 return NO_ERROR;
             case BINDER_LIB_TEST_NOP_TRANSACTION_WAIT:
                 usleep(5000);
-                return NO_ERROR;
+                [[fallthrough]];
             case BINDER_LIB_TEST_NOP_TRANSACTION:
+                // oneway error codes should be ignored
+                if (flags & TF_ONE_WAY) {
+                    return UNKNOWN_ERROR;
+                }
                 return NO_ERROR;
             case BINDER_LIB_TEST_DELAYED_CALL_BACK: {
                 // Note: this transaction is only designed for use with a
diff --git a/libs/binderdebug/Android.bp b/libs/binderdebug/Android.bp
new file mode 100644
index 0000000..343246a
--- /dev/null
+++ b/libs/binderdebug/Android.bp
@@ -0,0 +1,28 @@
+// 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_library {
+    name: "libbinderdebug",
+    vendor_available: true,
+    shared_libs: [
+        "libbase",
+        "libbinder",
+    ],
+    srcs: [
+        "BinderDebug.cpp",
+    ],
+    export_include_dirs: [
+        "include",
+    ],
+}
diff --git a/libs/binderdebug/BinderDebug.cpp b/libs/binderdebug/BinderDebug.cpp
new file mode 100644
index 0000000..b435dba
--- /dev/null
+++ b/libs/binderdebug/BinderDebug.cpp
@@ -0,0 +1,119 @@
+/*
+ * 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 <android-base/parseint.h>
+#include <android-base/strings.h>
+#include <binder/Binder.h>
+#include <sys/types.h>
+#include <fstream>
+#include <regex>
+
+#include <binderdebug/BinderDebug.h>
+
+namespace android {
+
+static std::string contextToString(BinderDebugContext context) {
+    switch (context) {
+        case BinderDebugContext::BINDER:
+            return "binder";
+        case BinderDebugContext::HWBINDER:
+            return "hwbinder";
+        case BinderDebugContext::VNDBINDER:
+            return "vndbinder";
+        default:
+            return std::string();
+    }
+}
+
+static status_t scanBinderContext(pid_t pid, const std::string& contextName,
+                                  std::function<void(const std::string&)> eachLine) {
+    std::ifstream ifs("/dev/binderfs/binder_logs/proc/" + std::to_string(pid));
+    if (!ifs.is_open()) {
+        ifs.open("/d/binder/proc/" + std::to_string(pid));
+        if (!ifs.is_open()) {
+            return -errno;
+        }
+    }
+    static const std::regex kContextLine("^context (\\w+)$");
+
+    bool isDesiredContext = false;
+    std::string line;
+    std::smatch match;
+    while (getline(ifs, line)) {
+        if (std::regex_search(line, match, kContextLine)) {
+            isDesiredContext = match.str(1) == contextName;
+            continue;
+        }
+        if (!isDesiredContext) {
+            continue;
+        }
+        eachLine(line);
+    }
+    return OK;
+}
+
+status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo* pidInfo) {
+    std::smatch match;
+    static const std::regex kReferencePrefix("^\\s*node \\d+:\\s+u([0-9a-f]+)\\s+c([0-9a-f]+)\\s+");
+    static const std::regex kThreadPrefix("^\\s*thread \\d+:\\s+l\\s+(\\d)(\\d)");
+    std::string contextStr = contextToString(context);
+    status_t ret = scanBinderContext(pid, contextStr, [&](const std::string& line) {
+        if (std::regex_search(line, match, kReferencePrefix)) {
+            const std::string& ptrString = "0x" + match.str(2); // use number after c
+            uint64_t ptr;
+            if (!::android::base::ParseUint(ptrString.c_str(), &ptr)) {
+                // Should not reach here, but just be tolerant.
+                return;
+            }
+            const std::string proc = " proc ";
+            auto pos = line.rfind(proc);
+            if (pos != std::string::npos) {
+                for (const std::string& pidStr : base::Split(line.substr(pos + proc.size()), " ")) {
+                    int32_t pid;
+                    if (!::android::base::ParseInt(pidStr, &pid)) {
+                        return;
+                    }
+                    pidInfo->refPids[ptr].push_back(pid);
+                }
+            }
+
+            return;
+        }
+        if (std::regex_search(line, match, kThreadPrefix)) {
+            // "1" is waiting in binder driver
+            // "2" is poll. It's impossible to tell if these are in use.
+            //     and HIDL default code doesn't use it.
+            bool isInUse = match.str(1) != "1";
+            // "0" is a thread that has called into binder
+            // "1" is looper thread
+            // "2" is main looper thread
+            bool isBinderThread = match.str(2) != "0";
+            if (!isBinderThread) {
+                return;
+            }
+            if (isInUse) {
+                pidInfo->threadUsage++;
+            }
+
+            pidInfo->threadCount++;
+            return;
+        }
+        return;
+    });
+    return ret;
+}
+
+} // namespace  android
diff --git a/libs/binderdebug/TEST_MAPPING b/libs/binderdebug/TEST_MAPPING
new file mode 100644
index 0000000..2f3353e
--- /dev/null
+++ b/libs/binderdebug/TEST_MAPPING
@@ -0,0 +1,7 @@
+{
+  "presubmit": [
+    {
+      "name": "libbinderdebug_test"
+    }
+  ]
+}
diff --git a/libs/binderdebug/include/binderdebug/BinderDebug.h b/libs/binderdebug/include/binderdebug/BinderDebug.h
new file mode 100644
index 0000000..14a0ef3
--- /dev/null
+++ b/libs/binderdebug/include/binderdebug/BinderDebug.h
@@ -0,0 +1,37 @@
+/*
+ * 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.
+ */
+#pragma once
+
+#include <map>
+#include <vector>
+
+namespace android {
+
+struct BinderPidInfo {
+    std::map<uint64_t, std::vector<pid_t>> refPids; // cookie -> processes which hold binder
+    uint32_t threadUsage;                           // number of threads in use
+    uint32_t threadCount;                           // number of threads total
+};
+
+enum class BinderDebugContext {
+    BINDER,
+    HWBINDER,
+    VNDBINDER,
+};
+
+status_t getBinderPidInfo(BinderDebugContext context, pid_t pid, BinderPidInfo* pidInfo);
+
+} // namespace  android
diff --git a/libs/binderdebug/tests/Android.bp b/libs/binderdebug/tests/Android.bp
new file mode 100644
index 0000000..4c06b1d
--- /dev/null
+++ b/libs/binderdebug/tests/Android.bp
@@ -0,0 +1,30 @@
+// 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_test {
+    name: "libbinderdebug_test",
+    test_suites: ["general-tests"],
+    srcs: [
+        "binderdebug_test.cpp",
+        "android/binderdebug/test/IControl.aidl",
+    ],
+    shared_libs: [
+        "libbase",
+        "libbinder",
+        "libutils",
+    ],
+    static_libs: ["libbinderdebug"],
+    cflags: ["-Wall", "-Werror"],
+    require_root: true,
+}
diff --git a/libs/binderdebug/tests/android/binderdebug/test/IControl.aidl b/libs/binderdebug/tests/android/binderdebug/test/IControl.aidl
new file mode 100644
index 0000000..8efeb63
--- /dev/null
+++ b/libs/binderdebug/tests/android/binderdebug/test/IControl.aidl
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+package android.binderdebug.test;
+
+interface IControl {
+    // Notifies the service to continue execution
+    void Continue();
+}
diff --git a/libs/binderdebug/tests/binderdebug_test.cpp b/libs/binderdebug/tests/binderdebug_test.cpp
new file mode 100644
index 0000000..ea799c0
--- /dev/null
+++ b/libs/binderdebug/tests/binderdebug_test.cpp
@@ -0,0 +1,90 @@
+/*
+ * 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 <binder/Binder.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <binder/IPCThreadState.h>
+#include <binderdebug/BinderDebug.h>
+#include <gtest/gtest.h>
+#include <semaphore.h>
+#include <thread>
+
+#include <android/binderdebug/test/BnControl.h>
+#include <android/binderdebug/test/IControl.h>
+
+namespace android {
+namespace binderdebug {
+namespace test {
+
+class Control : public BnControl {
+public:
+    Control() {sem_init(&s, 1, 0);};
+    ::android::binder::Status Continue() override;
+    sem_t s;
+};
+
+::android::binder::Status Control::Continue() {
+    IPCThreadState::self()->flushCommands();
+    sem_post(&s);
+    return binder::Status::ok();
+}
+
+TEST(BinderDebugTests, BinderPid) {
+    BinderPidInfo pidInfo;
+    const auto& status = getBinderPidInfo(BinderDebugContext::BINDER, getpid(), &pidInfo);
+    ASSERT_EQ(status, OK);
+    // There should be one referenced PID for servicemanager
+    EXPECT_TRUE(!pidInfo.refPids.empty());
+}
+
+TEST(BinderDebugTests, BinderThreads) {
+    BinderPidInfo pidInfo;
+    const auto& status = getBinderPidInfo(BinderDebugContext::BINDER, getpid(), &pidInfo);
+    ASSERT_EQ(status, OK);
+    EXPECT_TRUE(pidInfo.threadUsage <= pidInfo.threadCount);
+    // The second looper thread can sometimes take longer to spawn.
+    EXPECT_GE(pidInfo.threadCount, 1);
+}
+
+extern "C" {
+int main(int argc, char** argv) {
+    ::testing::InitGoogleTest(&argc, argv);
+
+    // Create a child/client process to call into the main process so we can ensure
+    // looper thread has been registered before attempting to get the BinderPidInfo
+    pid_t pid = fork();
+    if (pid == 0) {
+        sp<IBinder> binder = android::defaultServiceManager()->getService(String16("binderdebug"));
+        sp<IControl> service;
+        if (binder != nullptr) {
+            service = android::interface_cast<IControl>(binder);
+        }
+        service->Continue();
+        exit(0);
+    }
+    sp<Control> iface = new Control;
+    android::defaultServiceManager()->addService(String16("binderdebug"), iface);
+    android::ProcessState::self()->setThreadPoolMaxThreadCount(8);
+    ProcessState::self()->startThreadPool();
+    sem_wait(&iface->s);
+
+    return RUN_ALL_TESTS();
+}
+} // extern "C"
+} // namespace  test
+} // namespace  binderdebug
+} // namespace  android
diff --git a/libs/gralloc/types/include/gralloctypes/Gralloc4.h b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
index 1a7c2c9..2f418ac 100644
--- a/libs/gralloc/types/include/gralloctypes/Gralloc4.h
+++ b/libs/gralloc/types/include/gralloctypes/Gralloc4.h
@@ -32,202 +32,6 @@
 #include <android/hardware/graphics/mapper/4.0/IMapper.h>
 
 namespace android {
-
-/**
- * Define equality operators for Stable AIDL types.
- */
-inline bool operator==(const aidl::android::hardware::graphics::common::ExtendableType& lhs,
-                const aidl::android::hardware::graphics::common::ExtendableType& rhs) {
-    return !std::strcmp(lhs.name.c_str(), rhs.name.c_str()) && lhs.value == rhs.value;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::ExtendableType& lhs,
-                const aidl::android::hardware::graphics::common::ExtendableType& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLayoutComponent& lhs,
-                const aidl::android::hardware::graphics::common::PlaneLayoutComponent& rhs) {
-    if (lhs.type.name != rhs.type.name) {
-        return false;
-    }
-    if (lhs.type.value != rhs.type.value) {
-        return false;
-    }
-    if (lhs.sizeInBits != rhs.sizeInBits) {
-        return false;
-    }
-    if (lhs.offsetInBits != rhs.offsetInBits) {
-        return false;
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::PlaneLayoutComponent& lhs,
-                const aidl::android::hardware::graphics::common::PlaneLayoutComponent& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::Rect& lhs,
-                const aidl::android::hardware::graphics::common::Rect& rhs) {
-    if (lhs.left != rhs.left) {
-        return false;
-    }
-    if (lhs.top != rhs.top) {
-        return false;
-    }
-    if (lhs.right != rhs.right) {
-        return false;
-    }
-    if (lhs.bottom != rhs.bottom) {
-        return false;
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::Rect& lhs,
-                const aidl::android::hardware::graphics::common::Rect& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const std::vector<aidl::android::hardware::graphics::common::Rect>& lhs,
-                const std::vector<aidl::android::hardware::graphics::common::Rect>& rhs) {
-    if (lhs.size() != rhs.size()) {
-        return false;
-    }
-    for (size_t i = 0; i < lhs.size(); i++) {
-        if (lhs[i] != rhs[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-inline bool operator!=(const std::vector<aidl::android::hardware::graphics::common::Rect>& lhs,
-                const std::vector<aidl::android::hardware::graphics::common::Rect>& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::PlaneLayout& lhs,
-                const aidl::android::hardware::graphics::common::PlaneLayout& rhs) {
-    if (lhs.offsetInBytes != rhs.offsetInBytes) {
-        return false;
-    }
-    if (lhs.sampleIncrementInBits != rhs.sampleIncrementInBits) {
-        return false;
-    }
-    if (lhs.strideInBytes != rhs.strideInBytes) {
-        return false;
-    }
-    if (lhs.widthInSamples != rhs.widthInSamples) {
-        return false;
-    }
-    if (lhs.heightInSamples != rhs.heightInSamples) {
-        return false;
-    }
-    if (lhs.totalSizeInBytes != rhs.totalSizeInBytes) {
-        return false;
-    }
-    if (lhs.horizontalSubsampling != rhs.horizontalSubsampling) {
-        return false;
-    }
-    if (lhs.verticalSubsampling != rhs.verticalSubsampling) {
-        return false;
-    }
-    if (lhs.components.size() != rhs.components.size()) {
-        return false;
-    }
-    for (size_t i = 0; i < lhs.components.size(); i++) {
-        if (lhs.components[i] != rhs.components[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::PlaneLayout& lhs,
-                const aidl::android::hardware::graphics::common::PlaneLayout& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& lhs,
-                const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& rhs) {
-    if (lhs.size() != rhs.size()) {
-        return false;
-    }
-    for (size_t i = 0; i < lhs.size(); i++) {
-        if (lhs[i] != rhs[i]) {
-            return false;
-        }
-    }
-    return true;
-}
-
-inline bool operator!=(const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& lhs,
-                const std::vector<aidl::android::hardware::graphics::common::PlaneLayout>& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::XyColor& lhs,
-                const aidl::android::hardware::graphics::common::XyColor& rhs) {
-    if (lhs.x != rhs.x) {
-        return false;
-    }
-    if (lhs.y != rhs.y) {
-        return false;
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::XyColor& lhs,
-                const aidl::android::hardware::graphics::common::XyColor& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::Smpte2086& lhs,
-                const aidl::android::hardware::graphics::common::Smpte2086& rhs) {
-    if (lhs.primaryRed != rhs.primaryRed) {
-        return false;
-    }
-    if (lhs.primaryGreen != rhs.primaryGreen) {
-        return false;
-    }
-    if (lhs.primaryBlue != rhs.primaryBlue) {
-        return false;
-    }
-    if (lhs.whitePoint != rhs.whitePoint) {
-        return false;
-    }
-    if (lhs.maxLuminance != rhs.maxLuminance) {
-        return false;
-    }
-    if (lhs.minLuminance != rhs.minLuminance) {
-        return false;
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::Smpte2086& lhs,
-                const aidl::android::hardware::graphics::common::Smpte2086& rhs) {
-    return !(lhs == rhs);
-}
-
-inline bool operator==(const aidl::android::hardware::graphics::common::Cta861_3& lhs,
-                const aidl::android::hardware::graphics::common::Cta861_3& rhs) {
-    if (lhs.maxContentLightLevel != rhs.maxContentLightLevel) {
-        return false;
-    }
-    if (lhs.maxFrameAverageLightLevel != rhs.maxFrameAverageLightLevel) {
-        return false;
-    }
-    return true;
-}
-
-inline bool operator!=(const aidl::android::hardware::graphics::common::Cta861_3& lhs,
-                const aidl::android::hardware::graphics::common::Cta861_3& rhs) {
-    return !(lhs == rhs);
-}
-
 namespace gralloc4 {
 
 #define GRALLOC4_STANDARD_METADATA_TYPE "android.hardware.graphics.common.StandardMetadataType"
diff --git a/libs/gui/BLASTBufferQueue.cpp b/libs/gui/BLASTBufferQueue.cpp
index b9ab561..bf0386f 100644
--- a/libs/gui/BLASTBufferQueue.cpp
+++ b/libs/gui/BLASTBufferQueue.cpp
@@ -42,6 +42,10 @@
 // Macros to include adapter info in log messages
 #define BQA_LOGV(x, ...) \
     ALOGV("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
+// enable logs for a single layer
+//#define BQA_LOGV(x, ...) \
+//    ALOGV_IF((strstr(mName.c_str(), "SurfaceView") != nullptr), "[%s](f:%u,a:%u) " x, \
+//              mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
 #define BQA_LOGE(x, ...) \
     ALOGE("[%s](f:%u,a:%u) " x, mName.c_str(), mNumFrameAvailable, mNumAcquired, ##__VA_ARGS__)
 
@@ -123,7 +127,7 @@
         mProducer->setMaxDequeuedBufferCount(2);
     }
     mBufferItemConsumer =
-        new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER, 1, true);
+        new BLASTBufferItemConsumer(mConsumer, GraphicBuffer::USAGE_HW_COMPOSER, 1, false);
     static int32_t id = 0;
     auto consumerName = mName + "(BLAST Consumer)" + std::to_string(id);
     id++;
@@ -248,7 +252,8 @@
 
     BufferItem bufferItem;
 
-    status_t status = mBufferItemConsumer->acquireBuffer(&bufferItem, -1, false);
+    status_t status =
+            mBufferItemConsumer->acquireBuffer(&bufferItem, 0 /* expectedPresent */, false);
     if (status != OK) {
         BQA_LOGE("Failed to acquire a buffer, err=%s", statusToString(status).c_str());
         return;
@@ -289,6 +294,9 @@
     mLastBufferScalingMode = bufferItem.mScalingMode;
 
     t->setBuffer(mSurfaceControl, buffer);
+    t->setDataspace(mSurfaceControl, static_cast<ui::Dataspace>(bufferItem.mDataSpace));
+    t->setHdrMetadata(mSurfaceControl, bufferItem.mHdrMetadata);
+    t->setSurfaceDamageRegion(mSurfaceControl, bufferItem.mSurfaceDamage);
     t->setAcquireFence(mSurfaceControl,
                        bufferItem.mFence ? new Fence(bufferItem.mFence->dup()) : Fence::NO_FENCE);
     t->addTransactionCompletedCallback(transactionCallbackThunk, static_cast<void*>(this));
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index e46a415..405658b 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -1230,6 +1230,21 @@
 
         return remote()->transact(BnSurfaceComposer::ADD_TRANSACTION_TRACE_LISTENER, data, &reply);
     }
+
+    /**
+     * Get priority of the RenderEngine in surface flinger.
+     */
+    virtual int getGPUContextPriority() {
+        Parcel data, reply;
+        data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
+        status_t err =
+                remote()->transact(BnSurfaceComposer::GET_GPU_CONTEXT_PRIORITY, data, &reply);
+        if (err != NO_ERROR) {
+            ALOGE("getGPUContextPriority failed to read data:  %s (%d)", strerror(-err), err);
+            return 0;
+        }
+        return reply.readInt32();
+    }
 };
 
 // Out-of-line virtual method definition to trigger vtable emission in this
@@ -2094,6 +2109,12 @@
 
             return addTransactionTraceListener(listener);
         }
+        case GET_GPU_CONTEXT_PRIORITY: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            int priority = getGPUContextPriority();
+            SAFE_PARCEL(reply->writeInt32, priority);
+            return NO_ERROR;
+        }
         default: {
             return BBinder::onTransact(code, data, reply, flags);
         }
diff --git a/libs/gui/ITransactionCompletedListener.cpp b/libs/gui/ITransactionCompletedListener.cpp
index 69f7894..2dacae1 100644
--- a/libs/gui/ITransactionCompletedListener.cpp
+++ b/libs/gui/ITransactionCompletedListener.cpp
@@ -17,6 +17,8 @@
 #define LOG_TAG "ITransactionCompletedListener"
 //#define LOG_NDEBUG 0
 
+#include <gui/LayerState.h>
+#include <gui/ISurfaceComposer.h>
 #include <gui/ITransactionCompletedListener.h>
 
 namespace android {
@@ -90,61 +92,63 @@
     return err;
 }
 
-status_t SurfaceStats::writeToParcel(Parcel* output) const {
-    status_t err = output->writeStrongBinder(surfaceControl);
-    if (err != NO_ERROR) {
-        return err;
-    }
-    err = output->writeInt64(acquireTime);
-    if (err != NO_ERROR) {
-        return err;
-    }
-    if (previousReleaseFence) {
-        err = output->writeBool(true);
-        if (err != NO_ERROR) {
-            return err;
-        }
-        err = output->write(*previousReleaseFence);
-    } else {
-        err = output->writeBool(false);
-    }
-    err = output->writeUint32(transformHint);
-    if (err != NO_ERROR) {
-        return err;
-    }
+JankData::JankData() :
+        frameVsyncId(ISurfaceComposer::INVALID_VSYNC_ID),
+        jankType(JankType::None) {
+}
 
-    err = output->writeParcelable(eventStats);
-    return err;
+status_t JankData::writeToParcel(Parcel* output) const {
+    SAFE_PARCEL(output->writeInt64, frameVsyncId);
+    SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(jankType));
+    return NO_ERROR;
+}
+
+status_t JankData::readFromParcel(const Parcel* input) {
+    SAFE_PARCEL(input->readInt64, &frameVsyncId);
+    int32_t jankTypeInt;
+    SAFE_PARCEL(input->readInt32, &jankTypeInt);
+    jankType = static_cast<JankType>(jankTypeInt);
+    return NO_ERROR;
+}
+
+status_t SurfaceStats::writeToParcel(Parcel* output) const {
+    SAFE_PARCEL(output->writeStrongBinder, surfaceControl);
+    SAFE_PARCEL(output->writeInt64, acquireTime);
+    if (previousReleaseFence) {
+        SAFE_PARCEL(output->writeBool, true);
+        SAFE_PARCEL(output->write, *previousReleaseFence);
+    } else {
+        SAFE_PARCEL(output->writeBool, false);
+    }
+    SAFE_PARCEL(output->writeUint32, transformHint);
+    SAFE_PARCEL(output->writeParcelable, eventStats);
+    SAFE_PARCEL(output->writeInt32, static_cast<int32_t>(jankData.size()));
+    for (const auto& data : jankData) {
+        SAFE_PARCEL(output->writeParcelable, data);
+    }
+    return NO_ERROR;
 }
 
 status_t SurfaceStats::readFromParcel(const Parcel* input) {
-    status_t err = input->readStrongBinder(&surfaceControl);
-    if (err != NO_ERROR) {
-        return err;
-    }
-    err = input->readInt64(&acquireTime);
-    if (err != NO_ERROR) {
-        return err;
-    }
+    SAFE_PARCEL(input->readStrongBinder, &surfaceControl);
+    SAFE_PARCEL(input->readInt64, &acquireTime);
     bool hasFence = false;
-    err = input->readBool(&hasFence);
-    if (err != NO_ERROR) {
-        return err;
-    }
+    SAFE_PARCEL(input->readBool, &hasFence);
     if (hasFence) {
         previousReleaseFence = new Fence();
-        err = input->read(*previousReleaseFence);
-        if (err != NO_ERROR) {
-            return err;
-        }
+        SAFE_PARCEL(input->read, *previousReleaseFence);
     }
-    err = input->readUint32(&transformHint);
-    if (err != NO_ERROR) {
-        return err;
-    }
+    SAFE_PARCEL(input->readUint32, &transformHint);
+    SAFE_PARCEL(input->readParcelable, &eventStats);
 
-    err = input->readParcelable(&eventStats);
-    return err;
+    int32_t jankData_size = 0;
+    SAFE_PARCEL_READ_SIZE(input->readInt32, &jankData_size, input->dataSize());
+    for (int i = 0; i < jankData_size; i++) {
+        JankData data;
+        SAFE_PARCEL(input->readParcelable, &data);
+        jankData.push_back(data);
+    }
+    return NO_ERROR;
 }
 
 status_t TransactionStats::writeToParcel(Parcel* output) const {
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 47a08ab..0d370d3 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -125,6 +125,9 @@
     return DefaultComposerClient::getComposerClient();
 }
 
+JankDataListener::~JankDataListener() {
+}
+
 // ---------------------------------------------------------------------------
 
 // TransactionCompletedListener does not use ANDROID_SINGLETON_STATIC_INSTANCE because it needs
@@ -174,6 +177,23 @@
     return callbackId;
 }
 
+void TransactionCompletedListener::addJankListener(const sp<JankDataListener>& listener,
+                                                   sp<SurfaceControl> surfaceControl) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    mJankListeners.insert({surfaceControl->getHandle(), listener});
+}
+
+void TransactionCompletedListener::removeJankListener(const sp<JankDataListener>& listener) {
+    std::lock_guard<std::mutex> lock(mMutex);
+    for (auto it = mJankListeners.begin(); it != mJankListeners.end();) {
+        if (it->second == listener) {
+            it = mJankListeners.erase(it);
+        } else {
+            it++;
+        }
+    }
+}
+
 void TransactionCompletedListener::addSurfaceControlToCallbacks(
         const sp<SurfaceControl>& surfaceControl,
         const std::unordered_set<CallbackId>& callbackIds) {
@@ -189,6 +209,7 @@
 
 void TransactionCompletedListener::onTransactionCompleted(ListenerStats listenerStats) {
     std::unordered_map<CallbackId, CallbackTranslation> callbacksMap;
+    std::multimap<sp<IBinder>, sp<JankDataListener>> jankListenersMap;
     {
         std::lock_guard<std::mutex> lock(mMutex);
 
@@ -204,6 +225,7 @@
          * sp<SurfaceControl> that could possibly exist for the callbacks.
          */
         callbacksMap = mCallbacks;
+        jankListenersMap = mJankListeners;
         for (const auto& transactionStats : listenerStats.transactionStats) {
             for (auto& callbackId : transactionStats.callbackIds) {
                 mCallbacks.erase(callbackId);
@@ -236,6 +258,13 @@
             callbackFunction(transactionStats.latchTime, transactionStats.presentFence,
                              surfaceControlStats);
         }
+        for (const auto& surfaceStats : transactionStats.surfaceStats) {
+            if (surfaceStats.jankData.empty()) continue;
+            for (auto it = jankListenersMap.find(surfaceStats.surfaceControl);
+                    it != jankListenersMap.end(); it++) {
+                it->second->onJankDataAvailable(surfaceStats.jankData);
+            }
+        }
     }
 }
 
@@ -1959,6 +1988,10 @@
                                                                           lightRadius);
 }
 
+int SurfaceComposerClient::getGPUContextPriority() {
+    return ComposerService::getComposerService()->getGPUContextPriority();
+}
+
 // ----------------------------------------------------------------------------
 
 status_t ScreenshotClient::captureDisplay(const DisplayCaptureArgs& captureArgs,
diff --git a/libs/gui/include/gui/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index 86e3a25..7d25d61 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -504,6 +504,11 @@
      */
     virtual status_t addTransactionTraceListener(
             const sp<gui::ITransactionTraceListener>& listener) = 0;
+
+    /**
+     * Gets priority of the RenderEngine in SurfaceFlinger.
+     */
+    virtual int getGPUContextPriority() = 0;
 };
 
 // ----------------------------------------------------------------------------
@@ -565,6 +570,7 @@
         ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN,
         SET_FRAME_TIMELINE_VSYNC,
         ADD_TRANSACTION_TRACE_LISTENER,
+        GET_GPU_CONTEXT_PRIORITY,
         // Always append new enum to the end.
     };
 
diff --git a/libs/gui/include/gui/ITransactionCompletedListener.h b/libs/gui/include/gui/ITransactionCompletedListener.h
index c58634b..26b3840 100644
--- a/libs/gui/include/gui/ITransactionCompletedListener.h
+++ b/libs/gui/include/gui/ITransactionCompletedListener.h
@@ -16,6 +16,8 @@
 
 #pragma once
 
+#include "JankInfo.h"
+
 #include <binder/IInterface.h>
 #include <binder/Parcel.h>
 #include <binder/Parcelable.h>
@@ -57,6 +59,27 @@
     nsecs_t dequeueReadyTime;
 };
 
+/**
+ * Jank information representing SurfaceFlinger's jank classification about frames for a specific
+ * surface.
+ */
+class JankData : public Parcelable {
+public:
+    status_t writeToParcel(Parcel* output) const override;
+    status_t readFromParcel(const Parcel* input) override;
+
+    JankData();
+    JankData(int64_t frameVsyncId, JankType jankType)
+          : frameVsyncId(frameVsyncId),
+            jankType(jankType) {}
+
+    // Identifier for the frame submitted with Transaction.setFrameTimelineVsyncId
+    int64_t frameVsyncId;
+
+    // The type of jank occurred
+    JankType jankType;
+};
+
 class SurfaceStats : public Parcelable {
 public:
     status_t writeToParcel(Parcel* output) const override;
@@ -64,18 +87,21 @@
 
     SurfaceStats() = default;
     SurfaceStats(const sp<IBinder>& sc, nsecs_t time, const sp<Fence>& prevReleaseFence,
-                 uint32_t hint, FrameEventHistoryStats frameEventStats)
+                 uint32_t hint, FrameEventHistoryStats frameEventStats,
+                 std::vector<JankData> jankData)
           : surfaceControl(sc),
             acquireTime(time),
             previousReleaseFence(prevReleaseFence),
             transformHint(hint),
-            eventStats(frameEventStats) {}
+            eventStats(frameEventStats),
+            jankData(std::move(jankData)) {}
 
     sp<IBinder> surfaceControl;
     nsecs_t acquireTime = -1;
     sp<Fence> previousReleaseFence;
     uint32_t transformHint = 0;
     FrameEventHistoryStats eventStats;
+    std::vector<JankData> jankData;
 };
 
 class TransactionStats : public Parcelable {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 2eb97f2..3ee4a39 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -185,6 +185,11 @@
     static bool getProtectedContentSupport();
 
     /**
+     * Gets the context priority of surface flinger's render engine.
+     */
+    static int getGPUContextPriority();
+
+    /**
      * Uncaches a buffer in ISurfaceComposer. It must be uncached via a transaction so that it is
      * in order with other transactions that use buffers.
      */
@@ -619,6 +624,12 @@
 
 // ---------------------------------------------------------------------------
 
+class JankDataListener : public VirtualLightRefBase {
+public:
+    virtual ~JankDataListener() = 0;
+    virtual void onJankDataAvailable(const std::vector<JankData>& jankData) = 0;
+};
+
 class TransactionCompletedListener : public BnTransactionCompletedListener {
     TransactionCompletedListener();
 
@@ -637,6 +648,7 @@
     };
 
     std::unordered_map<CallbackId, CallbackTranslation> mCallbacks GUARDED_BY(mMutex);
+    std::multimap<sp<IBinder>, sp<JankDataListener>> mJankListeners GUARDED_BY(mMutex);
 
 public:
     static sp<TransactionCompletedListener> getInstance();
@@ -652,6 +664,18 @@
     void addSurfaceControlToCallbacks(const sp<SurfaceControl>& surfaceControl,
                                       const std::unordered_set<CallbackId>& callbackIds);
 
+    /*
+     * Adds a jank listener to be informed about SurfaceFlinger's jank classification for a specific
+     * surface. Jank classifications arrive as part of the transaction callbacks about previous
+     * frames submitted to this Surface.
+     */
+    void addJankListener(const sp<JankDataListener>& listener, sp<SurfaceControl> surfaceControl);
+
+    /**
+     * Removes a jank listener previously added to addJankCallback.
+     */
+    void removeJankListener(const sp<JankDataListener>& listener);
+
     // Overrides BnTransactionCompletedListener's onTransactionCompleted
     void onTransactionCompleted(ListenerStats stats) override;
 };
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index c39b0b5..c75c46c 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -95,6 +95,15 @@
         return std::make_unique<InputSurface>(surfaceControl, width, height);
     }
 
+    static std::unique_ptr<InputSurface> makeBlastInputSurface(const sp<SurfaceComposerClient> &scc,
+                                                               int width, int height) {
+        sp<SurfaceControl> surfaceControl =
+                scc->createSurface(String8("Test Buffer Surface"), width, height,
+                                   PIXEL_FORMAT_RGBA_8888,
+                                   ISurfaceComposerClient::eFXSurfaceBufferState);
+        return std::make_unique<InputSurface>(surfaceControl, width, height);
+    }
+
     static std::unique_ptr<InputSurface> makeContainerInputSurface(
             const sp<SurfaceComposerClient> &scc, int width, int height) {
         sp<SurfaceControl> surfaceControl =
@@ -180,13 +189,13 @@
         t.apply(true);
     }
 
-    void showAt(int x, int y) {
+    void showAt(int x, int y, Rect crop = Rect(0, 0, 100, 100)) {
         SurfaceComposerClient::Transaction t;
         t.show(mSurfaceControl);
         t.setInputWindowInfo(mSurfaceControl, mInputInfo);
         t.setLayer(mSurfaceControl, LAYER_BASE);
         t.setPosition(mSurfaceControl, x, y);
-        t.setCrop_legacy(mSurfaceControl, Rect(0, 0, 100, 100));
+        t.setCrop_legacy(mSurfaceControl, crop);
         t.setAlpha(mSurfaceControl, 1);
         t.apply(true);
     }
@@ -684,4 +693,34 @@
     surface->expectTap(1, 10);
 }
 
+TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_bql) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+
+    std::unique_ptr<InputSurface> bufferSurface =
+            InputSurface::makeBufferInputSurface(mComposerClient, 0, 0);
+    bufferSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
+    bufferSurface->mInputInfo.ownerUid = 22222;
+
+    surface->showAt(10, 10);
+    bufferSurface->showAt(50, 50, Rect::EMPTY_RECT);
+
+    injectTap(11, 11);
+    surface->expectTap(1, 1);
+}
+
+TEST_F(InputSurfacesTest, touch_not_obscured_with_zero_sized_blast) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+
+    std::unique_ptr<InputSurface> bufferSurface =
+            InputSurface::makeBlastInputSurface(mComposerClient, 0, 0);
+    bufferSurface->mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCHABLE;
+    bufferSurface->mInputInfo.ownerUid = 22222;
+
+    surface->showAt(10, 10);
+    bufferSurface->showAt(50, 50, Rect::EMPTY_RECT);
+
+    injectTap(11, 11);
+    surface->expectTap(1, 1);
+}
+
 } // namespace android::test
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index ce3afa2..7761db8 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -887,6 +887,8 @@
         return NO_ERROR;
     }
 
+    int getGPUContextPriority() override { return 0; };
+
 protected:
     IBinder* onAsBinder() override { return nullptr; }
 
diff --git a/libs/input/android/os/IInputConstants.aidl b/libs/input/android/os/IInputConstants.aidl
index 82c220f..6316b59 100644
--- a/libs/input/android/os/IInputConstants.aidl
+++ b/libs/input/android/os/IInputConstants.aidl
@@ -21,4 +21,11 @@
 interface IInputConstants
 {
     const int DEFAULT_DISPATCHING_TIMEOUT_MILLIS = 5000; // 5 seconds
+
+    // Compatibility changes.
+    /**
+      * TODO(b/157929241): remove this before closing the bug. This is needed temporarily
+      * to identify apps that are using this flag.
+      */
+    const long BLOCK_FLAG_SLIPPERY = 157929241;
 }
diff --git a/libs/renderengine/Android.bp b/libs/renderengine/Android.bp
index b878150..0e74c63 100644
--- a/libs/renderengine/Android.bp
+++ b/libs/renderengine/Android.bp
@@ -81,6 +81,9 @@
         "skia/AutoBackendTexture.cpp",
         "skia/SkiaRenderEngine.cpp",
         "skia/SkiaGLRenderEngine.cpp",
+        "skia/debug/CaptureTimer.cpp",
+        "skia/debug/CommonPool.cpp",
+        "skia/debug/SkiaCapture.cpp",
         "skia/filters/BlurFilter.cpp",
         "skia/filters/LinearEffect.cpp",
     ],
@@ -94,6 +97,7 @@
     cflags: [
         "-fvisibility=hidden",
         "-Werror=format",
+        "-Wno-unused-parameter",
     ],
     srcs: [
         ":librenderengine_sources",
diff --git a/libs/renderengine/gl/ProgramCache.cpp b/libs/renderengine/gl/ProgramCache.cpp
index 7fc0499..5ff9240 100644
--- a/libs/renderengine/gl/ProgramCache.cpp
+++ b/libs/renderengine/gl/ProgramCache.cpp
@@ -740,15 +740,6 @@
         if (needs.isOpaque()) {
             fs << "gl_FragColor.a = 1.0;";
         }
-        if (needs.hasAlpha()) {
-            // modulate the current alpha value with alpha set
-            if (needs.isPremultiplied()) {
-                // ... and the color too if we're premultiplied
-                fs << "gl_FragColor *= color.a;";
-            } else {
-                fs << "gl_FragColor.a *= color.a;";
-            }
-        }
     }
 
     if (needs.hasTransformMatrix() || (needs.getInputTF() != needs.getOutputTF()) ||
@@ -768,6 +759,23 @@
         }
     }
 
+    /*
+     * Whether applying layer alpha before or after color transform doesn't matter,
+     * as long as we can undo premultiplication. But we cannot un-premultiply
+     * for color transform if the layer alpha = 0, e.g. 0 / (0 + 0.0019) = 0.
+     */
+    if (!needs.drawShadows()) {
+        if (needs.hasAlpha()) {
+            // modulate the current alpha value with alpha set
+            if (needs.isPremultiplied()) {
+                // ... and the color too if we're premultiplied
+                fs << "gl_FragColor *= color.a;";
+            } else {
+                fs << "gl_FragColor.a *= color.a;";
+            }
+        }
+    }
+
     if (needs.hasRoundedCorners()) {
         if (needs.isPremultiplied()) {
             fs << "gl_FragColor *= vec4(applyCornerRadius(outCropCoords));";
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index 11b8e44..ef12fd2 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -31,10 +31,17 @@
 #include <ui/Transform.h>
 
 /**
- * Allows to set RenderEngine backend to GLES (default) or Vulkan (NOT yet supported).
+ * Allows to set RenderEngine backend to GLES (default) or SkiaGL (NOT yet supported).
  */
 #define PROPERTY_DEBUG_RENDERENGINE_BACKEND "debug.renderengine.backend"
 
+/**
+ * Turns on recording of skia commands in SkiaGL version of the RE. This property
+ * defines number of milliseconds for the recording to take place. A non zero value
+ * turns on the recording.
+ */
+#define PROPERTY_DEBUG_RENDERENGINE_CAPTURE_SKIA_MS "debug.renderengine.capture_skia_ms"
+
 struct ANativeWindowBuffer;
 
 namespace android {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 8dc0c68..ee0a70a 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -15,19 +15,19 @@
  */
 
 //#define LOG_NDEBUG 0
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
 #include <cstdint>
 #include <memory>
 
 #include "SkImageInfo.h"
 #include "log/log_main.h"
 #include "system/graphics-base-v1.0.h"
-#undef LOG_TAG
-#define LOG_TAG "RenderEngine"
-#define ATRACE_TAG ATRACE_TAG_GRAPHICS
 
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
-#include <GLES2/gl2.h>
 #include <sync/sync.h>
 #include <ui/BlurRegion.h>
 #include <ui/GraphicBuffer.h>
@@ -35,6 +35,8 @@
 #include "../gl/GLExtensions.h"
 #include "SkiaGLRenderEngine.h"
 #include "filters/BlurFilter.h"
+#include "filters/LinearEffect.h"
+#include "skia/debug/SkiaCapture.h"
 
 #include <GrContextOptions.h>
 #include <SkCanvas.h>
@@ -46,17 +48,9 @@
 #include <SkShadowUtils.h>
 #include <SkSurface.h>
 #include <gl/GrGLInterface.h>
-#include <sync/sync.h>
-#include <ui/GraphicBuffer.h>
-#include <utils/Trace.h>
 
 #include <cmath>
 
-#include "../gl/GLExtensions.h"
-#include "SkiaGLRenderEngine.h"
-#include "filters/BlurFilter.h"
-#include "filters/LinearEffect.h"
-
 bool checkGlError(const char* op, int lineNumber);
 
 namespace android {
@@ -482,7 +476,7 @@
                                                                         : ui::Dataspace::SRGB,
                                                                 mGrContext.get());
 
-    auto canvas = surface->getCanvas();
+    SkCanvas* canvas = mCapture.tryCapture(surface.get());
     // Clear the entire canvas with a transparent black to prevent ghost images.
     canvas->clear(SK_ColorTRANSPARENT);
     canvas->save();
@@ -550,8 +544,6 @@
         if (layer->source.buffer.buffer) {
             ATRACE_NAME("DrawImage");
             const auto& item = layer->source.buffer;
-            const auto bufferWidth = item.buffer->getBounds().width();
-            const auto bufferHeight = item.buffer->getBounds().height();
             std::shared_ptr<AutoBackendTexture::LocalRef> imageTextureRef = nullptr;
             auto iter = mTextureCache.find(item.buffer->getId());
             if (iter != mTextureCache.end()) {
@@ -583,50 +575,23 @@
                                                                  ? kPremul_SkAlphaType
                                                                  : kUnpremul_SkAlphaType),
                                         mGrContext.get());
-            SkMatrix matrix;
-            if (layer->geometry.roundedCornersRadius > 0) {
-                const auto roundedRect = getRoundedRect(layer);
-                matrix.setTranslate(roundedRect.getBounds().left() - dest.left(),
-                                    roundedRect.getBounds().top() - dest.top());
-            } else {
-                matrix.setIdentity();
-            }
 
             auto texMatrix = getSkM44(item.textureTransform).asM33();
-
-            // b/171404534, scale to fix the layer
-            matrix.postScale(bounds.getWidth() / bufferWidth, bounds.getHeight() / bufferHeight);
-
             // textureTansform was intended to be passed directly into a shader, so when
             // building the total matrix with the textureTransform we need to first
             // normalize it, then apply the textureTransform, then scale back up.
-            matrix.postScale(1.0f / bufferWidth, 1.0f / bufferHeight);
+            texMatrix.preScale(1.0f / bounds.getWidth(), 1.0f / bounds.getHeight());
+            texMatrix.postScale(image->width(), image->height());
 
-            auto rotatedBufferWidth = bufferWidth;
-            auto rotatedBufferHeight = bufferHeight;
-
-            // Swap the buffer width and height if we're rotating, so that we
-            // scale back up by the correct factors post-rotation.
-            if (texMatrix.getSkewX() <= -0.5f || texMatrix.getSkewX() >= 0.5f) {
-                std::swap(rotatedBufferWidth, rotatedBufferHeight);
-                // TODO: clean this up.
-                // GLESRenderEngine specifies its texture coordinates in
-                // CW orientation under OpenGL conventions, when they probably should have
-                // been CCW instead. The net result is that orientation
-                // transforms are applied in the reverse
-                // direction to render the correct result, because SurfaceFlinger uses the inverse
-                // of the display transform to correct for that. But this means that
-                // the tex transform passed by SkiaGLRenderEngine will rotate
-                // individual layers in the reverse orientation. Hack around it
-                // by injected a 180 degree rotation, but ultimately this is
-                // a bug in how SurfaceFlinger invokes the RenderEngine
-                // interface, so the proper fix should live there, and GLESRenderEngine
-                // should be fixed accordingly.
-                matrix.postRotate(180, 0.5, 0.5);
+            SkMatrix matrix;
+            if (!texMatrix.invert(&matrix)) {
+                matrix = texMatrix;
             }
+            // The shader does not respect the translation, so we add it to the texture
+            // transform for the SkImage. This will make sure that the correct layer contents
+            // are drawn in the correct part of the screen.
+            matrix.postTranslate(layer->geometry.boundaries.left, layer->geometry.boundaries.top);
 
-            matrix.postConcat(texMatrix);
-            matrix.postScale(rotatedBufferWidth, rotatedBufferHeight);
             sk_sp<SkShader> shader;
 
             if (layer->source.buffer.useTextureFiltering) {
@@ -635,7 +600,7 @@
                                                    {SkFilterMode::kLinear, SkMipmapMode::kNone}),
                                            &matrix);
             } else {
-                shader = image->makeShader(matrix);
+                shader = image->makeShader(SkSamplingOptions(), matrix);
             }
 
             if (mUseColorManagement &&
@@ -688,19 +653,19 @@
             drawShadow(canvas, rect, layer->geometry.roundedCornersRadius, layer->shadow);
         }
 
+        // Push the clipRRect onto the clip stack. Draw the image. Pop the clip.
         if (layer->geometry.roundedCornersRadius > 0) {
-            canvas->drawRRect(getRoundedRect(layer), paint);
-        } else {
-            canvas->drawRect(dest, paint);
+            canvas->clipRRect(getRoundedRect(layer), true);
         }
-
+        canvas->drawRect(dest, paint);
         canvas->restore();
     }
+    canvas->restore();
+    mCapture.endCapture();
     {
         ATRACE_NAME("flush surface");
         surface->flush();
     }
-    canvas->restore();
 
     if (drawFence != nullptr) {
         *drawFence = flush();
@@ -736,7 +701,7 @@
 }
 
 inline SkRRect SkiaGLRenderEngine::getRoundedRect(const LayerSettings* layer) {
-    const auto rect = getSkRect(layer->geometry.boundaries);
+    const auto rect = getSkRect(layer->geometry.roundedCornersCrop);
     const auto cornerRadius = layer->geometry.roundedCornersRadius;
     return SkRRect::MakeRectXY(rect, cornerRadius, cornerRadius);
 }
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index ef06bfa..b53250e 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -35,6 +35,7 @@
 #include "SkiaRenderEngine.h"
 #include "android-base/macros.h"
 #include "filters/BlurFilter.h"
+#include "skia/debug/SkiaCapture.h"
 #include "skia/filters/LinearEffect.h"
 
 namespace android {
@@ -116,6 +117,8 @@
     sk_sp<GrDirectContext> mProtectedGrContext;
 
     bool mInProtectedContext = false;
+    // Object to capture commands send to Skia.
+    SkiaCapture mCapture;
 };
 
 } // namespace skia
diff --git a/libs/renderengine/skia/debug/CaptureTimer.cpp b/libs/renderengine/skia/debug/CaptureTimer.cpp
new file mode 100644
index 0000000..11bcdb8
--- /dev/null
+++ b/libs/renderengine/skia/debug/CaptureTimer.cpp
@@ -0,0 +1,47 @@
+/*
+ * 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 "CaptureTimer.h"
+
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include "CommonPool.h"
+
+#include <thread>
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+void CaptureTimer::setTimeout(TimeoutCallback function, std::chrono::milliseconds delay) {
+    this->clear = false;
+    CommonPool::post([=]() {
+        if (this->clear) return;
+        std::this_thread::sleep_for(delay);
+        if (this->clear) return;
+        function();
+    });
+}
+
+void CaptureTimer::stop() {
+    this->clear = true;
+}
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/skia/debug/CaptureTimer.h b/libs/renderengine/skia/debug/CaptureTimer.h
new file mode 100644
index 0000000..a0aa302
--- /dev/null
+++ b/libs/renderengine/skia/debug/CaptureTimer.h
@@ -0,0 +1,43 @@
+/*
+ * 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 <chrono>
+#include <functional>
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+/**
+ * Simple timer that times out after a given delay and executes a void
+ * callback function.
+ */
+class CaptureTimer {
+    bool clear = false;
+
+public:
+    using TimeoutCallback = std::function<void()>;
+    // Start the timeout.
+    void setTimeout(TimeoutCallback function, std::chrono::milliseconds delay);
+    // Stop and clean up.
+    void stop();
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/skia/debug/CommonPool.cpp b/libs/renderengine/skia/debug/CommonPool.cpp
new file mode 100644
index 0000000..bf15300
--- /dev/null
+++ b/libs/renderengine/skia/debug/CommonPool.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 "CommonPool.h"
+
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <sys/resource.h>
+#include <utils/Trace.h>
+
+#include <system/thread_defs.h>
+#include <array>
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+CommonPool::CommonPool() {
+    ATRACE_CALL();
+
+    CommonPool* pool = this;
+    // Create 2 workers
+    for (int i = 0; i < THREAD_COUNT; i++) {
+        std::thread worker([pool, i] {
+            {
+                std::array<char, 20> name{"reTask"};
+                snprintf(name.data(), name.size(), "reTask%d", i);
+                auto self = pthread_self();
+                pthread_setname_np(self, name.data());
+                setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_FOREGROUND);
+            }
+            pool->workerLoop();
+        });
+        worker.detach();
+    }
+}
+
+CommonPool& CommonPool::instance() {
+    static CommonPool pool;
+    return pool;
+}
+
+void CommonPool::post(Task&& task) {
+    instance().enqueue(std::move(task));
+}
+
+void CommonPool::enqueue(Task&& task) {
+    std::unique_lock lock(mLock);
+    while (mWorkQueue.size() > QUEUE_SIZE) {
+        lock.unlock();
+        ALOGW("Queue is full: %d, waiting before adding more tasks.", QUEUE_SIZE);
+        usleep(100);
+        lock.lock();
+    }
+    mWorkQueue.push(std::move(task));
+    if (mWaitingThreads == THREAD_COUNT || (mWaitingThreads > 0 && mWorkQueue.size() > 1)) {
+        mCondition.notify_one();
+    }
+}
+
+void CommonPool::workerLoop() {
+    std::unique_lock lock(mLock);
+    while (true) {
+        if (mWorkQueue.size() == 0) {
+            mWaitingThreads++;
+            mCondition.wait(lock);
+            mWaitingThreads--;
+        }
+        // Need to double-check that work is still available now that we have the lock
+        // It may have already been grabbed by a different thread
+        while (mWorkQueue.size() > 0) {
+            auto work = mWorkQueue.front();
+            mWorkQueue.pop();
+            lock.unlock();
+            work();
+            lock.lock();
+        }
+    }
+}
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
\ No newline at end of file
diff --git a/libs/renderengine/skia/debug/CommonPool.h b/libs/renderengine/skia/debug/CommonPool.h
new file mode 100644
index 0000000..7fc3d23
--- /dev/null
+++ b/libs/renderengine/skia/debug/CommonPool.h
@@ -0,0 +1,70 @@
+/*
+ * 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 <log/log.h>
+
+#include <condition_variable>
+#include <functional>
+#include <future>
+#include <mutex>
+#include <queue>
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+namespace {
+#define PREVENT_COPY_AND_ASSIGN(Type) \
+private:                              \
+    Type(const Type&) = delete;       \
+    void operator=(const Type&) = delete
+} // namespace
+
+/**
+ * Shamelessly copied from HWUI to execute Skia Capturing on the back thread in
+ * a safe manner.
+ */
+class CommonPool {
+    PREVENT_COPY_AND_ASSIGN(CommonPool);
+
+public:
+    using Task = std::function<void()>;
+    static constexpr auto THREAD_COUNT = 2;
+    static constexpr auto QUEUE_SIZE = 128;
+
+    static void post(Task&& func);
+
+private:
+    static CommonPool& instance();
+
+    CommonPool();
+    ~CommonPool() {}
+
+    void enqueue(Task&&);
+
+    void workerLoop();
+
+    std::mutex mLock;
+    std::condition_variable mCondition;
+    int mWaitingThreads = 0;
+    std::queue<Task> mWorkQueue;
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/skia/debug/README.md b/libs/renderengine/skia/debug/README.md
new file mode 100644
index 0000000..4719e34
--- /dev/null
+++ b/libs/renderengine/skia/debug/README.md
@@ -0,0 +1,17 @@
+This library turns on recording of skia commands in SkiaGL version of the RE.
+The debug property defines number of milliseconds for the recording to take place.
+A non zero value turns on the recording. The recording will stop after MS specified.
+To reset the recording, set the capture_skia_ms flag to a new time. When recording
+is finished, the capture_skia_ms flag will be set to 0 to avoid circular recording.
+
+In order to allow the process to write files onto the device run:
+adb shell setenforce 0
+
+To start recording run:
+adb shell setprop debug.renderengine.capture_skia_ms 1000
+
+File will be stored in the /data/user/ directory on the device:
+adb shell ls -al /data/user/
+
+To retrieve the data from the device:
+adb pull /data/user/re_skiacapture_<timestamp>.mskp
diff --git a/libs/renderengine/skia/debug/SkiaCapture.cpp b/libs/renderengine/skia/debug/SkiaCapture.cpp
new file mode 100644
index 0000000..8006a11
--- /dev/null
+++ b/libs/renderengine/skia/debug/SkiaCapture.cpp
@@ -0,0 +1,144 @@
+/*
+ * 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 "SkiaCapture.h"
+
+#undef LOG_TAG
+#define LOG_TAG "RenderEngine"
+#define ATRACE_TAG ATRACE_TAG_GRAPHICS
+
+#include <android-base/properties.h>
+#include <android-base/stringprintf.h>
+#include <log/log.h>
+#include <renderengine/RenderEngine.h>
+#include <utils/Trace.h>
+
+#include "CommonPool.h"
+#include "src/utils/SkMultiPictureDocument.h"
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+// The root of the filename to write a recorded SKP to. In order for this file to
+// be written to /data/user/, user must run 'adb shell setenforce 0' in the device.
+static const std::string CAPTURED_FILENAME_BASE = "/data/user/re_skiacapture";
+
+SkiaCapture::~SkiaCapture() {
+    mTimer.stop();
+}
+
+SkCanvas* SkiaCapture::tryCapture(SkSurface* surface) {
+    ATRACE_CALL();
+
+    // If we are not running yet, set up.
+    if (!mCaptureRunning) {
+        mTimerInterval = std::chrono::milliseconds(
+                base::GetIntProperty(PROPERTY_DEBUG_RENDERENGINE_CAPTURE_SKIA_MS, 0));
+        // Set up the multi-frame capture. If we fail to set it up, then just return canvas.
+        // If interval is 0, return surface.
+        if (CC_LIKELY(mTimerInterval == 0ms || !setupMultiFrameCapture())) {
+            return surface->getCanvas();
+        }
+        // Start the new timer. When timer expires, write to file.
+        mTimer.setTimeout(
+                [this] {
+                    endCapture();
+                    writeToFile();
+                    // To avoid going in circles, set the flag to 0. This way the capture can be
+                    // restarted just by setting the flag and without restarting the process.
+                    base::SetProperty(PROPERTY_DEBUG_RENDERENGINE_CAPTURE_SKIA_MS, "0");
+                },
+                mTimerInterval);
+    }
+
+    // Create a canvas pointer, fill it.
+    SkCanvas* pictureCanvas = mMultiPic->beginPage(surface->width(), surface->height());
+
+    // Setting up an nway canvas is common to any kind of capture.
+    mNwayCanvas = std::make_unique<SkNWayCanvas>(surface->width(), surface->height());
+    mNwayCanvas->addCanvas(surface->getCanvas());
+    mNwayCanvas->addCanvas(pictureCanvas);
+
+    return mNwayCanvas.get();
+}
+
+void SkiaCapture::endCapture() {
+    ATRACE_CALL();
+    // Don't end anything if we are not running.
+    if (!mCaptureRunning) {
+        return;
+    }
+    // Reset the canvas pointer.
+    mNwayCanvas.reset();
+    // End page.
+    if (mMultiPic) {
+        mMultiPic->endPage();
+    }
+}
+
+void SkiaCapture::writeToFile() {
+    ATRACE_CALL();
+    // Pass mMultiPic and mOpenMultiPicStream to a background thread, which will
+    // handle the heavyweight serialization work and destroy them.
+    // mOpenMultiPicStream is released to a bare pointer because keeping it in
+    // a smart pointer makes the lambda non-copyable. The lambda is only called
+    // once, so this is safe.
+    SkFILEWStream* stream = mOpenMultiPicStream.release();
+    CommonPool::post([doc = std::move(mMultiPic), stream] {
+        ALOGD("Finalizing multi frame SKP");
+        doc->close();
+        delete stream;
+        ALOGD("Multi frame SKP complete.");
+    });
+    mCaptureRunning = false;
+}
+
+bool SkiaCapture::setupMultiFrameCapture() {
+    ATRACE_CALL();
+    ALOGD("Set up multi-frame capture, ms = %llu", mTimerInterval.count());
+
+    std::string captureFile;
+    // Attach a timestamp to the file.
+    base::StringAppendF(&captureFile, "%s_%lld.mskp", CAPTURED_FILENAME_BASE.c_str(),
+                        std::chrono::steady_clock::now().time_since_epoch().count());
+    auto stream = std::make_unique<SkFILEWStream>(captureFile.c_str());
+    // We own this stream and need to hold it until close() finishes.
+    if (stream->isValid()) {
+        mOpenMultiPicStream = std::move(stream);
+        mSerialContext.reset(new SkSharingSerialContext());
+        SkSerialProcs procs;
+        procs.fImageProc = SkSharingSerialContext::serializeImage;
+        procs.fImageCtx = mSerialContext.get();
+        procs.fTypefaceProc = [](SkTypeface* tf, void* ctx) {
+            return tf->serialize(SkTypeface::SerializeBehavior::kDoIncludeData);
+        };
+        // SkDocuments don't take ownership of the streams they write.
+        // we need to keep it until after mMultiPic.close()
+        // procs is passed as a pointer, but just as a method of having an optional default.
+        // procs doesn't need to outlive this Make call.
+        mMultiPic = SkMakeMultiPictureDocument(mOpenMultiPicStream.get(), &procs);
+        mCaptureRunning = true;
+        return true;
+    } else {
+        ALOGE("Could not open \"%s\" for writing.", captureFile.c_str());
+        return false;
+    }
+}
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/skia/debug/SkiaCapture.h b/libs/renderengine/skia/debug/SkiaCapture.h
new file mode 100644
index 0000000..52717a7
--- /dev/null
+++ b/libs/renderengine/skia/debug/SkiaCapture.h
@@ -0,0 +1,70 @@
+/*
+ * 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 <SkDocument.h>
+#include <SkNWayCanvas.h>
+#include <SkSurface.h>
+#include <chrono>
+#include "CaptureTimer.h"
+#include "tools/SkSharingProc.h"
+
+namespace android {
+namespace renderengine {
+namespace skia {
+
+using namespace std::chrono_literals;
+
+/**
+ * Class that captures frames that are sent to Skia in Render Engine. It sets up
+ * a multi frame capture and writes it into a file on the device. The capture is
+ * done based on a timer.
+ */
+class SkiaCapture {
+    using Interval = std::chrono::milliseconds;
+
+public:
+    SkiaCapture() {}
+    virtual ~SkiaCapture();
+    // Called every frame. Normally returns early with screen canvas.
+    // But when capture is enabled, returns an nwaycanvas where commands are also recorded.
+    SkCanvas* tryCapture(SkSurface* surface);
+    // Called at the end of every frame.
+    void endCapture();
+
+private:
+    // Performs the first-frame work of a multi frame SKP capture. Returns true if successful.
+    bool setupMultiFrameCapture();
+
+    // Closes the recording and serializes sequence to a file.
+    void writeToFile();
+
+    // Multi frame serialization stream and writer used when serializing more than one frame.
+    std::unique_ptr<SkFILEWStream> mOpenMultiPicStream;
+    sk_sp<SkDocument> mMultiPic;
+    std::unique_ptr<SkSharingSerialContext> mSerialContext;
+    std::unique_ptr<SkNWayCanvas> mNwayCanvas;
+
+    // Capturing and interval control.
+    bool mCaptureRunning = false;
+    CaptureTimer mTimer;
+    Interval mTimerInterval = 0ms;
+};
+
+} // namespace skia
+} // namespace renderengine
+} // namespace android
diff --git a/libs/renderengine/tests/RenderEngineTest.cpp b/libs/renderengine/tests/RenderEngineTest.cpp
index 0e11c99..d9dfd8c 100644
--- a/libs/renderengine/tests/RenderEngineTest.cpp
+++ b/libs/renderengine/tests/RenderEngineTest.cpp
@@ -88,6 +88,45 @@
     }
 };
 
+class SkiaGLESRenderEngineFactory : public RenderEngineFactory {
+public:
+    std::string name() override { return "SkiaGLESRenderEngineFactory"; }
+
+    std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() override {
+        renderengine::RenderEngineCreationArgs reCreationArgs =
+                renderengine::RenderEngineCreationArgs::Builder()
+                        .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+                        .setImageCacheSize(1)
+                        .setEnableProtectedContext(false)
+                        .setPrecacheToneMapperShaderOnly(false)
+                        .setSupportsBackgroundBlur(true)
+                        .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
+                        .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::SKIA_GL)
+                        .build();
+        return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
+    }
+};
+
+class SkiaGLESCMRenderEngineFactory : public RenderEngineFactory {
+public:
+    std::string name() override { return "SkiaGLESCMRenderEngineFactory"; }
+
+    std::unique_ptr<renderengine::gl::GLESRenderEngine> createRenderEngine() override {
+        renderengine::RenderEngineCreationArgs reCreationArgs =
+                renderengine::RenderEngineCreationArgs::Builder()
+                        .setPixelFormat(static_cast<int>(ui::PixelFormat::RGBA_8888))
+                        .setImageCacheSize(1)
+                        .setEnableProtectedContext(false)
+                        .setPrecacheToneMapperShaderOnly(false)
+                        .setSupportsBackgroundBlur(true)
+                        .setContextPriority(renderengine::RenderEngine::ContextPriority::MEDIUM)
+                        .setRenderEngineType(renderengine::RenderEngine::RenderEngineType::SKIA_GL)
+                        .setUseColorManagerment(true)
+                        .build();
+        return renderengine::gl::GLESRenderEngine::create(reCreationArgs);
+    }
+};
+
 class RenderEngineTest : public ::testing::TestWithParam<std::shared_ptr<RenderEngineFactory>> {
 public:
     static sp<GraphicBuffer> allocateDefaultBuffer() {
@@ -367,6 +406,12 @@
     void fillBufferColorTransform();
 
     template <typename SourceVariant>
+    void fillBufferWithColorTransformZeroLayerAlpha();
+
+    template <typename SourceVariant>
+    void fillBufferColorTransformZeroLayerAlpha();
+
+    template <typename SourceVariant>
     void fillRedBufferWithRoundedCorners();
 
     template <typename SourceVariant>
@@ -726,6 +771,36 @@
 }
 
 template <typename SourceVariant>
+void RenderEngineTest::fillBufferWithColorTransformZeroLayerAlpha() {
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = Rect(1, 1);
+
+    std::vector<const renderengine::LayerSettings*> layers;
+
+    renderengine::LayerSettings layer;
+    layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+    SourceVariant::fillColor(layer, 0.5f, 0.25f, 0.125f, this);
+    layer.alpha = 0;
+
+    // construct a fake color matrix
+    // simple inverse color
+    settings.colorTransform = mat4(-1, 0, 0, 0, 0, -1, 0, 0, 0, 0, -1, 0, 1, 1, 1, 1);
+
+    layer.geometry.boundaries = Rect(1, 1).toFloatRect();
+
+    layers.push_back(&layer);
+
+    invokeDraw(settings, layers, mBuffer);
+}
+
+template <typename SourceVariant>
+void RenderEngineTest::fillBufferColorTransformZeroLayerAlpha() {
+    fillBufferWithColorTransformZeroLayerAlpha<SourceVariant>();
+    expectBufferColor(fullscreenRect(), 0, 0, 0, 0);
+}
+
+template <typename SourceVariant>
 void RenderEngineTest::fillRedBufferWithRoundedCorners() {
     renderengine::DisplaySettings settings;
     settings.physicalDisplay = fullscreenRect();
@@ -1045,7 +1120,9 @@
 
 INSTANTIATE_TEST_SUITE_P(PerRenderEngineType, RenderEngineTest,
                          testing::Values(std::make_shared<GLESRenderEngineFactory>(),
-                                         std::make_shared<GLESCMRenderEngineFactory>()));
+                                         std::make_shared<GLESCMRenderEngineFactory>(),
+                                         std::make_shared<SkiaGLESRenderEngineFactory>(),
+                                         std::make_shared<SkiaGLESCMRenderEngineFactory>()));
 
 TEST_P(RenderEngineTest, drawLayers_noLayersToDraw) {
     const auto& renderEngineFactory = GetParam();
@@ -1199,6 +1276,13 @@
     fillBufferWithRoundedCorners<ColorSourceVariant>();
 }
 
+TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_colorSource) {
+    const auto& renderEngineFactory = GetParam();
+    mRE = renderEngineFactory->createRenderEngine();
+
+    fillBufferColorTransformZeroLayerAlpha<ColorSourceVariant>();
+}
+
 TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_colorSource) {
     const auto& renderEngineFactory = GetParam();
     mRE = renderEngineFactory->createRenderEngine();
@@ -1296,6 +1380,12 @@
 
     fillBufferWithRoundedCorners<BufferSourceVariant<ForceOpaqueBufferVariant>>();
 }
+TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_opaqueBufferSource) {
+    const auto& renderEngineFactory = GetParam();
+    mRE = renderEngineFactory->createRenderEngine();
+
+    fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<ForceOpaqueBufferVariant>>();
+}
 
 TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_opaqueBufferSource) {
     const auto& renderEngineFactory = GetParam();
@@ -1395,6 +1485,13 @@
     fillBufferWithRoundedCorners<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
 }
 
+TEST_P(RenderEngineTest, drawLayers_fillBufferColorTransformZeroLayerAlpha_bufferSource) {
+    const auto& renderEngineFactory = GetParam();
+    mRE = renderEngineFactory->createRenderEngine();
+
+    fillBufferColorTransformZeroLayerAlpha<BufferSourceVariant<RelaxOpaqueBufferVariant>>();
+}
+
 TEST_P(RenderEngineTest, drawLayers_fillBufferAndBlurBackground_bufferSource) {
     const auto& renderEngineFactory = GetParam();
     mRE = renderEngineFactory->createRenderEngine();
@@ -1694,6 +1791,56 @@
     EXPECT_TRUE(mRE->isTextureNameKnownForTesting(texName));
 }
 
+TEST_P(RenderEngineTest, testRoundedCornersCrop) {
+    const auto& renderEngineFactory = GetParam();
+    mRE = renderEngineFactory->createRenderEngine();
+
+    renderengine::DisplaySettings settings;
+    settings.physicalDisplay = fullscreenRect();
+    settings.clip = fullscreenRect();
+    settings.outputDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+
+    std::vector<const renderengine::LayerSettings*> layers;
+
+    renderengine::LayerSettings redLayer;
+    redLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+    redLayer.geometry.boundaries = fullscreenRect().toFloatRect();
+    redLayer.geometry.roundedCornersRadius = 5.0f;
+    redLayer.geometry.roundedCornersCrop = fullscreenRect().toFloatRect();
+    // Red background.
+    redLayer.source.solidColor = half3(1.0f, 0.0f, 0.0f);
+    redLayer.alpha = 1.0f;
+
+    layers.push_back(&redLayer);
+
+    // Green layer with 1/3 size.
+    renderengine::LayerSettings greenLayer;
+    greenLayer.sourceDataspace = ui::Dataspace::V0_SRGB_LINEAR;
+    greenLayer.geometry.boundaries = fullscreenRect().toFloatRect();
+    greenLayer.geometry.roundedCornersRadius = 5.0f;
+    // Bottom right corner is not going to be rounded.
+    greenLayer.geometry.roundedCornersCrop =
+            Rect(DEFAULT_DISPLAY_WIDTH / 3, DEFAULT_DISPLAY_HEIGHT / 3, DEFAULT_DISPLAY_HEIGHT,
+                 DEFAULT_DISPLAY_HEIGHT)
+                    .toFloatRect();
+    greenLayer.source.solidColor = half3(0.0f, 1.0f, 0.0f);
+    greenLayer.alpha = 1.0f;
+
+    layers.push_back(&greenLayer);
+
+    invokeDraw(settings, layers, mBuffer);
+
+    // Corners should be ignored...
+    // Screen size: width is 128, height is 256.
+    expectBufferColor(Rect(0, 0, 1, 1), 0, 0, 0, 0);
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH - 1, 0, DEFAULT_DISPLAY_WIDTH, 1), 0, 0, 0, 0);
+    expectBufferColor(Rect(0, DEFAULT_DISPLAY_HEIGHT - 1, 1, DEFAULT_DISPLAY_HEIGHT), 0, 0, 0, 0);
+    // Bottom right corner is kept out of the clipping, and it's green.
+    expectBufferColor(Rect(DEFAULT_DISPLAY_WIDTH - 1, DEFAULT_DISPLAY_HEIGHT - 1,
+                           DEFAULT_DISPLAY_WIDTH, DEFAULT_DISPLAY_HEIGHT),
+                      0, 255, 0, 255);
+}
+
 } // namespace android
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
diff --git a/libs/sensorprivacy/OWNERS b/libs/sensorprivacy/OWNERS
new file mode 100644
index 0000000..be955f5
--- /dev/null
+++ b/libs/sensorprivacy/OWNERS
@@ -0,0 +1,3 @@
+cbrubaker@google.com
+evanseverson@google.com
+mpgroover@google.com
diff --git a/services/audiomanager/IAudioManager.cpp b/services/audiomanager/IAudioManager.cpp
index 6235f06..0d17265 100644
--- a/services/audiomanager/IAudioManager.cpp
+++ b/services/audiomanager/IAudioManager.cpp
@@ -84,11 +84,13 @@
         return remote()->transact(PLAYER_ATTRIBUTES, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
-    virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event) {
+    virtual status_t playerEvent(audio_unique_id_t piid, player_state_t event,
+            audio_port_handle_t deviceId) {
         Parcel data, reply;
         data.writeInterfaceToken(IAudioManager::getInterfaceDescriptor());
         data.writeInt32((int32_t) piid);
         data.writeInt32((int32_t) event);
+        data.writeInt32((int32_t) deviceId);
         return remote()->transact(PLAYER_EVENT, data, &reply, IBinder::FLAG_ONEWAY);
     }
 
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 96e6207..b640e9c 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -58,6 +58,7 @@
         "libstatslog",
         "libutils",
         "libui",
+        "lib-platform-compat-native-api",
     ],
     static_libs: [
         "libattestation",
diff --git a/services/inputflinger/VibrationElement.cpp b/services/inputflinger/VibrationElement.cpp
index aaf5834..17e1ad4 100644
--- a/services/inputflinger/VibrationElement.cpp
+++ b/services/inputflinger/VibrationElement.cpp
@@ -24,13 +24,28 @@
 using android::base::StringPrintf;
 
 namespace android {
+// VibrationElement implementations
+VibrationElement::VibrationElement(size_t channelNum) {
+    channels.reserve(channelNum);
+}
+
+VibrationElement::VibrationElement(const VibrationElement& other) {
+    duration = other.duration;
+    channels.resize(other.channels.size());
+    for (size_t i = 0; i < other.channels.size(); i++) {
+        channels[i].first = other.channels[i].first;
+        channels[i].second = other.channels[i].second;
+    }
+}
 
 const std::string VibrationElement::toString() const {
     std::string dump;
     dump += StringPrintf("[duration=%lldms, channels=[", duration.count());
 
     for (auto it = channels.begin(); it != channels.end(); ++it) {
-        dump += std::to_string(*it);
+        dump += std::to_string(it->first);
+        dump += " : ";
+        dump += std::to_string(it->second);
         if (std::next(it) != channels.end()) {
             dump += ", ";
         }
@@ -40,17 +55,79 @@
     return dump;
 }
 
-uint16_t VibrationElement::getMagnitude(size_t channelIdx) const {
-    if (channelIdx >= channels.size()) {
+uint16_t VibrationElement::getMagnitude(int32_t vibratorId) const {
+    auto it =
+            std::find_if(channels.begin(), channels.end(),
+                         [vibratorId](const std::pair<int32_t /*vibratorId*/, uint8_t /*amplitude*/>
+                                              pair) { return pair.first == vibratorId; });
+    if (it == channels.end()) {
         return 0;
     }
     // convert range [0,255] to [0,65535] (android framework to linux ff ranges)
-    return static_cast<uint16_t>(channels[channelIdx]) << 8;
+    return static_cast<uint16_t>(it->second) << 8;
 }
 
 bool VibrationElement::isOn() const {
     return std::any_of(channels.begin(), channels.end(),
-                       [](uint16_t channel) { return channel != 0; });
+                       [](const auto& channel) { return channel.second != 0; });
+}
+
+void VibrationElement::addChannel(int32_t vibratorId, uint8_t amplitude) {
+    channels.push_back(std::make_pair(vibratorId, amplitude));
+}
+
+bool VibrationElement::operator==(const VibrationElement& other) const {
+    if (duration != other.duration || channels.size() != other.channels.size()) {
+        return false;
+    }
+    for (size_t i = 0; i < CHANNEL_SIZE; i++) {
+        if (channels[i] != other.channels[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+bool VibrationElement::operator!=(const VibrationElement& other) const {
+    return !(*this == other);
+}
+
+// VibrationSequence implementations
+VibrationSequence::VibrationSequence(size_t length) {
+    pattern.reserve(length);
+}
+
+void VibrationSequence::operator=(const VibrationSequence& other) {
+    pattern = other.pattern;
+}
+
+bool VibrationSequence::operator==(const VibrationSequence& other) const {
+    if (pattern.size() != other.pattern.size()) {
+        return false;
+    }
+    for (size_t i = 0; i < pattern.size(); i++) {
+        if (pattern[i] != other.pattern[i]) {
+            return false;
+        }
+    }
+    return true;
+}
+
+void VibrationSequence::addElement(VibrationElement element) {
+    pattern.push_back(element);
+}
+
+const std::string VibrationSequence::toString() const {
+    std::string dump;
+    dump += "[";
+
+    for (const auto& element : pattern) {
+        dump += element.toString();
+        dump += " ";
+    }
+
+    dump += "]";
+    return dump;
 }
 
 } // namespace android
diff --git a/services/inputflinger/benchmarks/Android.bp b/services/inputflinger/benchmarks/Android.bp
index 9abf8b1..bd275a7 100644
--- a/services/inputflinger/benchmarks/Android.bp
+++ b/services/inputflinger/benchmarks/Android.bp
@@ -16,6 +16,7 @@
         "libstatslog",
         "libui",
         "libutils",
+        "lib-platform-compat-native-api",
     ],
     static_libs: [
         "libattestation",
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 9fea298..7c572b4 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -96,6 +96,8 @@
 
     void onPointerDownOutsideFocus(const sp<IBinder>& newToken) override {}
 
+    void setPointerCapture(bool enabled) override {}
+
     InputDispatcherConfiguration mConfig;
 };
 
diff --git a/services/inputflinger/dispatcher/Android.bp b/services/inputflinger/dispatcher/Android.bp
index ff9aac9..d467692 100644
--- a/services/inputflinger/dispatcher/Android.bp
+++ b/services/inputflinger/dispatcher/Android.bp
@@ -47,6 +47,7 @@
         "libstatslog",
         "libui",
         "libutils",
+        "lib-platform-compat-native-api",
     ],
     static_libs: [
         "libattestation",
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 29df00b..d8a6548 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -114,6 +114,22 @@
     return StringPrintf("FocusEvent(hasFocus=%s)", hasFocus ? "true" : "false");
 }
 
+// --- PointerCaptureChangedEntry ---
+
+// PointerCaptureChanged notifications always go to apps, so set the flag POLICY_FLAG_PASS_TO_USER
+// for all entries.
+PointerCaptureChangedEntry::PointerCaptureChangedEntry(int32_t id, nsecs_t eventTime,
+                                                       bool hasPointerCapture)
+      : EventEntry(id, Type::POINTER_CAPTURE_CHANGED, eventTime, POLICY_FLAG_PASS_TO_USER),
+        pointerCaptureEnabled(hasPointerCapture) {}
+
+PointerCaptureChangedEntry::~PointerCaptureChangedEntry() {}
+
+std::string PointerCaptureChangedEntry::getDescription() const {
+    return StringPrintf("PointerCaptureChangedEvent(pointerCaptureEnabled=%s)",
+                        pointerCaptureEnabled ? "true" : "false");
+}
+
 // --- KeyEntry ---
 
 KeyEntry::KeyEntry(int32_t id, nsecs_t eventTime, int32_t deviceId, uint32_t source,
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 0661709..fba5514 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -36,6 +36,7 @@
         FOCUS,
         KEY,
         MOTION,
+        POINTER_CAPTURE_CHANGED,
     };
 
     static const char* typeToString(Type type) {
@@ -50,6 +51,8 @@
                 return "KEY";
             case Type::MOTION:
                 return "MOTION";
+            case Type::POINTER_CAPTURE_CHANGED:
+                return "POINTER_CAPTURE_CHANGED";
         }
     }
 
@@ -115,6 +118,15 @@
     virtual ~FocusEntry();
 };
 
+struct PointerCaptureChangedEntry : EventEntry {
+    bool pointerCaptureEnabled;
+
+    PointerCaptureChangedEntry(int32_t id, nsecs_t eventTime, bool hasPointerCapture);
+    std::string getDescription() const override;
+
+    virtual ~PointerCaptureChangedEntry();
+};
+
 struct KeyEntry : EventEntry {
     int32_t deviceId;
     uint32_t source;
@@ -254,6 +266,7 @@
     sp<IBinder> oldToken;
     sp<IBinder> newToken;
     std::string obscuringPackage;
+    bool enabled;
 };
 
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 91e9536..ee5ada5 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -53,6 +53,8 @@
 #include <android-base/stringprintf.h>
 #include <android/os/IInputConstants.h>
 #include <binder/Binder.h>
+#include <binder/IServiceManager.h>
+#include <com/android/internal/compat/IPlatformCompatNative.h>
 #include <input/InputDevice.h>
 #include <input/InputWindow.h>
 #include <log/log.h>
@@ -79,8 +81,10 @@
 
 using android::base::StringPrintf;
 using android::os::BlockUntrustedTouchesMode;
+using android::os::IInputConstants;
 using android::os::InputEventInjectionResult;
 using android::os::InputEventInjectionSync;
+using com::android::internal::compat::IPlatformCompatNative;
 
 namespace android::inputdispatcher {
 
@@ -422,6 +426,15 @@
     return *lhs == *rhs;
 }
 
+static sp<IPlatformCompatNative> getCompatService() {
+    sp<IBinder> service(defaultServiceManager()->getService(String16("platform_compat_native")));
+    if (service == nullptr) {
+        ALOGE("Failed to link to compat service");
+        return nullptr;
+    }
+    return interface_cast<IPlatformCompatNative>(service);
+}
+
 // --- InputDispatcher ---
 
 InputDispatcher::InputDispatcher(const sp<InputDispatcherPolicyInterface>& policy)
@@ -440,7 +453,10 @@
         // initialize it here anyways.
         mInTouchMode(true),
         mMaximumObscuringOpacityForTouch(1.0f),
-        mFocusedDisplayId(ADISPLAY_ID_DEFAULT) {
+        mFocusedDisplayId(ADISPLAY_ID_DEFAULT),
+        mFocusedWindowRequestedPointerCapture(false),
+        mWindowTokenWithPointerCapture(nullptr),
+        mCompatService(getCompatService()) {
     mLooper = new Looper(false);
     mReporter = createInputReporter();
 
@@ -699,6 +715,14 @@
             break;
         }
 
+        case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
+            const auto typedEntry =
+                    std::static_pointer_cast<PointerCaptureChangedEntry>(mPendingEvent);
+            dispatchPointerCaptureChangedLocked(currentTime, typedEntry, dropReason);
+            done = true;
+            break;
+        }
+
         case EventEntry::Type::KEY: {
             std::shared_ptr<KeyEntry> keyEntry = std::static_pointer_cast<KeyEntry>(mPendingEvent);
             if (isAppSwitchDue) {
@@ -848,7 +872,8 @@
             break;
         }
         case EventEntry::Type::CONFIGURATION_CHANGED:
-        case EventEntry::Type::DEVICE_RESET: {
+        case EventEntry::Type::DEVICE_RESET:
+        case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
             // nothing to do
             break;
         }
@@ -954,6 +979,10 @@
             ALOGI("Dropped event because it is stale.");
             reason = "inbound event was dropped because it is stale";
             break;
+        case DropReason::NO_POINTER_CAPTURE:
+            ALOGI("Dropped event because there is no window with Pointer Capture.");
+            reason = "inbound event was dropped because there is no window with Pointer Capture";
+            break;
         case DropReason::NOT_DROPPED: {
             LOG_ALWAYS_FATAL("Should not be dropping a NOT_DROPPED event");
             return;
@@ -977,6 +1006,9 @@
             }
             break;
         }
+        case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
+            break;
+        }
         case EventEntry::Type::FOCUS:
         case EventEntry::Type::CONFIGURATION_CHANGED:
         case EventEntry::Type::DEVICE_RESET: {
@@ -1162,6 +1194,55 @@
     dispatchEventLocked(currentTime, entry, {target});
 }
 
+void InputDispatcher::dispatchPointerCaptureChangedLocked(
+        nsecs_t currentTime, const std::shared_ptr<PointerCaptureChangedEntry>& entry,
+        DropReason& dropReason) {
+    const bool haveWindowWithPointerCapture = mWindowTokenWithPointerCapture != nullptr;
+    if (entry->pointerCaptureEnabled == haveWindowWithPointerCapture) {
+        LOG_ALWAYS_FATAL_IF(mFocusedWindowRequestedPointerCapture,
+                            "The Pointer Capture state has already been dispatched to the window.");
+        // Pointer capture was already forcefully disabled because of focus change.
+        dropReason = DropReason::NOT_DROPPED;
+        return;
+    }
+
+    // Set drop reason for early returns
+    dropReason = DropReason::NO_POINTER_CAPTURE;
+
+    sp<IBinder> token;
+    if (entry->pointerCaptureEnabled) {
+        // Enable Pointer Capture
+        if (!mFocusedWindowRequestedPointerCapture) {
+            // This can happen if a window requests capture and immediately releases capture.
+            ALOGW("No window requested Pointer Capture.");
+            return;
+        }
+        token = getValueByKey(mFocusedWindowTokenByDisplay, mFocusedDisplayId);
+        LOG_ALWAYS_FATAL_IF(!token, "Cannot find focused window for Pointer Capture.");
+        mWindowTokenWithPointerCapture = token;
+    } else {
+        // Disable Pointer Capture
+        token = mWindowTokenWithPointerCapture;
+        mWindowTokenWithPointerCapture = nullptr;
+        mFocusedWindowRequestedPointerCapture = false;
+    }
+
+    auto channel = getInputChannelLocked(token);
+    if (channel == nullptr) {
+        // Window has gone away, clean up Pointer Capture state.
+        mWindowTokenWithPointerCapture = nullptr;
+        mFocusedWindowRequestedPointerCapture = false;
+        return;
+    }
+    InputTarget target;
+    target.inputChannel = channel;
+    target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
+    entry->dispatchInProgress = true;
+    dispatchEventLocked(currentTime, entry, {target});
+
+    dropReason = DropReason::NOT_DROPPED;
+}
+
 bool InputDispatcher::dispatchKeyLocked(nsecs_t currentTime, std::shared_ptr<KeyEntry> entry,
                                         DropReason* dropReason, nsecs_t* nextWakeupTime) {
     // Preprocessing.
@@ -1469,6 +1550,7 @@
             displayId = motionEntry.displayId;
             break;
         }
+        case EventEntry::Type::POINTER_CAPTURE_CHANGED:
         case EventEntry::Type::FOCUS:
         case EventEntry::Type::CONFIGURATION_CHANGED:
         case EventEntry::Type::DEVICE_RESET: {
@@ -1863,6 +1945,8 @@
                 }
                 if (isWindowObscuredAtPointLocked(newTouchedWindowHandle, x, y)) {
                     targetFlags |= InputTarget::FLAG_WINDOW_IS_OBSCURED;
+                } else if (isWindowObscuredLocked(newTouchedWindowHandle)) {
+                    targetFlags |= InputTarget::FLAG_WINDOW_IS_PARTIALLY_OBSCURED;
                 }
 
                 BitSet32 pointerIds;
@@ -2352,8 +2436,10 @@
 }
 
 void InputDispatcher::pokeUserActivityLocked(const EventEntry& eventEntry) {
-    if (eventEntry.type == EventEntry::Type::FOCUS) {
-        // Focus events are passed to apps, but do not represent user activity.
+    if (eventEntry.type == EventEntry::Type::FOCUS ||
+        eventEntry.type == EventEntry::Type::POINTER_CAPTURE_CHANGED) {
+        // Focus or pointer capture changed events are passed to apps, but do not represent user
+        // activity.
         return;
     }
     int32_t displayId = getTargetDisplayId(eventEntry);
@@ -2391,7 +2477,8 @@
         }
         case EventEntry::Type::FOCUS:
         case EventEntry::Type::CONFIGURATION_CHANGED:
-        case EventEntry::Type::DEVICE_RESET: {
+        case EventEntry::Type::DEVICE_RESET:
+        case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
             LOG_ALWAYS_FATAL("%s events are not user activity",
                              EventEntry::typeToString(eventEntry.type));
             break;
@@ -2603,7 +2690,8 @@
 
             break;
         }
-        case EventEntry::Type::FOCUS: {
+        case EventEntry::Type::FOCUS:
+        case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
             break;
         }
         case EventEntry::Type::CONFIGURATION_CHANGED:
@@ -2807,6 +2895,7 @@
                 reportTouchEventForStatistics(motionEntry);
                 break;
             }
+
             case EventEntry::Type::FOCUS: {
                 const FocusEntry& focusEntry = static_cast<const FocusEntry&>(eventEntry);
                 status = connection->inputPublisher.publishFocusEvent(dispatchEntry->seq,
@@ -2816,6 +2905,15 @@
                 break;
             }
 
+            case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
+                const auto& captureEntry =
+                        static_cast<const PointerCaptureChangedEntry&>(eventEntry);
+                status = connection->inputPublisher
+                                 .publishCaptureEvent(dispatchEntry->seq, captureEntry.id,
+                                                      captureEntry.pointerCaptureEnabled);
+                break;
+            }
+
             case EventEntry::Type::CONFIGURATION_CHANGED:
             case EventEntry::Type::DEVICE_RESET: {
                 LOG_ALWAYS_FATAL("Should never start dispatch cycles for %s events",
@@ -3110,8 +3208,10 @@
                                          static_cast<const MotionEntry&>(*cancelationEventEntry));
                 break;
             }
-            case EventEntry::Type::FOCUS: {
-                LOG_ALWAYS_FATAL("Canceling focus events is not supported");
+            case EventEntry::Type::FOCUS:
+            case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
+                LOG_ALWAYS_FATAL("Canceling %s events is not supported",
+                                 EventEntry::typeToString(cancelationEventEntry->type));
                 break;
             }
             case EventEntry::Type::CONFIGURATION_CHANGED:
@@ -3171,7 +3271,8 @@
             case EventEntry::Type::KEY:
             case EventEntry::Type::FOCUS:
             case EventEntry::Type::CONFIGURATION_CHANGED:
-            case EventEntry::Type::DEVICE_RESET: {
+            case EventEntry::Type::DEVICE_RESET:
+            case EventEntry::Type::POINTER_CAPTURE_CHANGED: {
                 LOG_ALWAYS_FATAL("%s event should not be found inside Connections's queue",
                                      EventEntry::typeToString(downEventEntry->type));
                 break;
@@ -3548,7 +3649,17 @@
           args->enabled ? "true" : "false");
 #endif
 
-    // TODO(prabirmsp): Implement.
+    bool needWake;
+    { // acquire lock
+        std::scoped_lock _l(mLock);
+        auto entry = std::make_unique<PointerCaptureChangedEntry>(args->id, args->eventTime,
+                                                                  args->enabled);
+        needWake = enqueueInboundEventLocked(std::move(entry));
+    } // release lock
+
+    if (needWake) {
+        mLooper->wake();
+    }
 }
 
 InputEventInjectionResult InputDispatcher::injectInputEvent(
@@ -4010,8 +4121,8 @@
         const std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>>& handlesPerDisplay) {
     { // acquire lock
         std::scoped_lock _l(mLock);
-        for (auto const& i : handlesPerDisplay) {
-            setInputWindowsLocked(i.second, i.first);
+        for (const auto& [displayId, handles] : handlesPerDisplay) {
+            setInputWindowsLocked(handles, displayId);
         }
     }
     // Wake up poll loop since it may need to make new input dispatching choices.
@@ -4113,6 +4224,18 @@
                 ALOGD("Window went away: %s", oldWindowHandle->getName().c_str());
             }
             oldWindowHandle->releaseChannel();
+            // To avoid making too many calls into the compat framework, only
+            // check for window flags when windows are going away.
+            // TODO(b/157929241) : delete this. This is only needed temporarily
+            // in order to gather some data about the flag usage
+            if (oldWindowHandle->getInfo()->flags.test(InputWindowInfo::Flag::SLIPPERY)) {
+                ALOGW("%s has FLAG_SLIPPERY. Please report this in b/157929241",
+                      oldWindowHandle->getName().c_str());
+                if (mCompatService != nullptr) {
+                    mCompatService->reportChangeByUid(IInputConstants::BLOCK_FLAG_SLIPPERY,
+                                                      oldWindowHandle->getInfo()->ownerUid);
+                }
+            }
         }
     }
 }
@@ -4430,6 +4553,24 @@
     return dump;
 }
 
+std::string InputDispatcher::dumpPointerCaptureStateLocked() {
+    std::string dump;
+
+    dump += StringPrintf(INDENT "FocusedWindowRequestedPointerCapture: %s\n",
+                         toString(mFocusedWindowRequestedPointerCapture));
+
+    std::string windowName = "None";
+    if (mWindowTokenWithPointerCapture) {
+        const sp<InputWindowHandle> captureWindowHandle =
+                getWindowHandleLocked(mWindowTokenWithPointerCapture);
+        windowName = captureWindowHandle ? captureWindowHandle->getName().c_str()
+                                         : "token has capture without window";
+    }
+    dump += StringPrintf(INDENT "CurrentWindowWithPointerCapture: %s\n", windowName.c_str());
+
+    return dump;
+}
+
 void InputDispatcher::dumpDispatchStateLocked(std::string& dump) {
     dump += StringPrintf(INDENT "DispatchEnabled: %s\n", toString(mDispatchEnabled));
     dump += StringPrintf(INDENT "DispatchFrozen: %s\n", toString(mDispatchFrozen));
@@ -4453,6 +4594,7 @@
 
     dump += dumpFocusedWindowsLocked();
     dump += dumpPendingFocusRequestsLocked();
+    dump += dumpPointerCaptureStateLocked();
 
     if (!mTouchStatesByDisplay.empty()) {
         dump += StringPrintf(INDENT "TouchStatesByDisplay:\n");
@@ -4834,6 +4976,39 @@
     return OK;
 }
 
+void InputDispatcher::requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) {
+    { // acquire lock
+        std::scoped_lock _l(mLock);
+        if (DEBUG_FOCUS) {
+            const sp<InputWindowHandle> windowHandle = getWindowHandleLocked(windowToken);
+            ALOGI("Request to %s Pointer Capture from: %s.", enabled ? "enable" : "disable",
+                  windowHandle != nullptr ? windowHandle->getName().c_str()
+                                          : "token without window");
+        }
+
+        const sp<IBinder> focusedToken =
+                getValueByKey(mFocusedWindowTokenByDisplay, mFocusedDisplayId);
+        if (focusedToken != windowToken) {
+            ALOGW("Ignoring request to %s Pointer Capture: window does not have focus.",
+                  enabled ? "enable" : "disable");
+            return;
+        }
+
+        if (enabled == mFocusedWindowRequestedPointerCapture) {
+            ALOGW("Ignoring request to %s Pointer Capture: "
+                  "window has %s requested pointer capture.",
+                  enabled ? "enable" : "disable", enabled ? "already" : "not");
+            return;
+        }
+
+        mFocusedWindowRequestedPointerCapture = enabled;
+        setPointerCaptureLocked(enabled);
+    } // release lock
+
+    // Wake the thread to process command entries.
+    mLooper->wake();
+}
+
 std::optional<int32_t> InputDispatcher::findGestureMonitorDisplayByTokenLocked(
         const sp<IBinder>& token) {
     for (const auto& it : mGestureMonitorsByDisplay) {
@@ -5552,11 +5727,50 @@
         enqueueFocusEventLocked(newFocusedToken, true /*hasFocus*/, reason);
     }
 
+    // If a window has pointer capture, then it must have focus. We need to ensure that this
+    // contract is upheld when pointer capture is being disabled due to a loss of window focus.
+    // If the window loses focus before it loses pointer capture, then the window can be in a state
+    // where it has pointer capture but not focus, violating the contract. Therefore we must
+    // dispatch the pointer capture event before the focus event. Since focus events are added to
+    // the front of the queue (above), we add the pointer capture event to the front of the queue
+    // after the focus events are added. This ensures the pointer capture event ends up at the
+    // front.
+    disablePointerCaptureForcedLocked();
+
     if (mFocusedDisplayId == displayId) {
         notifyFocusChangedLocked(oldFocusedToken, newFocusedToken);
     }
 }
 
+void InputDispatcher::disablePointerCaptureForcedLocked() {
+    if (!mFocusedWindowRequestedPointerCapture && !mWindowTokenWithPointerCapture) {
+        return;
+    }
+
+    ALOGD_IF(DEBUG_FOCUS, "Disabling Pointer Capture because the window lost focus.");
+
+    if (mFocusedWindowRequestedPointerCapture) {
+        mFocusedWindowRequestedPointerCapture = false;
+        setPointerCaptureLocked(false);
+    }
+
+    if (!mWindowTokenWithPointerCapture) {
+        // No need to send capture changes because no window has capture.
+        return;
+    }
+
+    if (mPendingEvent != nullptr) {
+        // Move the pending event to the front of the queue. This will give the chance
+        // for the pending event to be dropped if it is a captured event.
+        mInboundQueue.push_front(mPendingEvent);
+        mPendingEvent = nullptr;
+    }
+
+    auto entry = std::make_unique<PointerCaptureChangedEntry>(mIdGenerator.nextId(), now(),
+                                                              false /* hasCapture */);
+    mInboundQueue.push_front(std::move(entry));
+}
+
 /**
  * Checks if the window token can be focused on a display. The token can be focused if there is
  * at least one window handle that is visible with the same token and all window handles with the
@@ -5600,4 +5814,21 @@
 
     return FocusResult::OK;
 }
+
+void InputDispatcher::setPointerCaptureLocked(bool enabled) {
+    std::unique_ptr<CommandEntry> commandEntry = std::make_unique<CommandEntry>(
+            &InputDispatcher::doSetPointerCaptureLockedInterruptible);
+    commandEntry->enabled = enabled;
+    postCommandLocked(std::move(commandEntry));
+}
+
+void InputDispatcher::doSetPointerCaptureLockedInterruptible(
+        android::inputdispatcher::CommandEntry* commandEntry) {
+    mLock.unlock();
+
+    mPolicy->setPointerCapture(commandEntry->enabled);
+
+    mLock.lock();
+}
+
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 9aaae74..5d37645 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -32,6 +32,7 @@
 #include "TouchedWindow.h"
 
 #include <attestation/HmacKeyManager.h>
+#include <com/android/internal/compat/IPlatformCompatNative.h>
 #include <input/Input.h>
 #include <input/InputApplication.h>
 #include <input/InputTransport.h>
@@ -126,6 +127,7 @@
             int32_t displayId, bool isGestureMonitor, const std::string& name) override;
     virtual status_t removeInputChannel(const sp<IBinder>& connectionToken) override;
     virtual status_t pilferPointers(const sp<IBinder>& token) override;
+    virtual void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) override;
 
     std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const;
 
@@ -137,6 +139,7 @@
         DISABLED,
         BLOCKED,
         STALE,
+        NO_POINTER_CAPTURE,
     };
 
     enum class FocusResult {
@@ -350,6 +353,21 @@
     // Top focused display.
     int32_t mFocusedDisplayId GUARDED_BY(mLock);
 
+    // Whether the focused window on the focused display has requested Pointer Capture.
+    // The state of this variable should always be in sync with the state of Pointer Capture in the
+    // policy, which is updated through setPointerCaptureLocked(enabled).
+    bool mFocusedWindowRequestedPointerCapture GUARDED_BY(mLock);
+
+    // The window token that has Pointer Capture.
+    // This should be in sync with PointerCaptureChangedEvents dispatched to the input channel.
+    sp<IBinder> mWindowTokenWithPointerCapture GUARDED_BY(mLock);
+
+    // Disable Pointer Capture as a result of loss of window focus.
+    void disablePointerCaptureForcedLocked() REQUIRES(mLock);
+
+    // Set the Pointer Capture state in the Policy.
+    void setPointerCaptureLocked(bool enabled) REQUIRES(mLock);
+
     // Dispatcher state at time of last ANR.
     std::string mLastAnrState GUARDED_BY(mLock);
 
@@ -369,6 +387,9 @@
                               DropReason* dropReason, nsecs_t* nextWakeupTime) REQUIRES(mLock);
     void dispatchFocusLocked(nsecs_t currentTime, std::shared_ptr<FocusEntry> entry)
             REQUIRES(mLock);
+    void dispatchPointerCaptureChangedLocked(
+            nsecs_t currentTime, const std::shared_ptr<PointerCaptureChangedEntry>& entry,
+            DropReason& dropReason) REQUIRES(mLock);
     void dispatchEventLocked(nsecs_t currentTime, std::shared_ptr<EventEntry> entry,
                              const std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
 
@@ -532,6 +553,7 @@
     void logDispatchStateLocked() REQUIRES(mLock);
     std::string dumpFocusedWindowsLocked() REQUIRES(mLock);
     std::string dumpPendingFocusRequestsLocked() REQUIRES(mLock);
+    std::string dumpPointerCaptureStateLocked() REQUIRES(mLock);
 
     // Registration.
     void removeMonitorChannelLocked(const sp<IBinder>& connectionToken) REQUIRES(mLock);
@@ -574,6 +596,7 @@
     void doInterceptKeyBeforeDispatchingLockedInterruptible(CommandEntry* commandEntry)
             REQUIRES(mLock);
     void doDispatchCycleFinishedLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
+    void doSetPointerCaptureLockedInterruptible(CommandEntry* commandEntry) REQUIRES(mLock);
     bool afterKeyEventLockedInterruptible(const sp<Connection>& connection,
                                           DispatchEntry* dispatchEntry, KeyEntry& keyEntry,
                                           bool handled) REQUIRES(mLock);
@@ -596,6 +619,7 @@
     void traceWaitQueueLength(const sp<Connection>& connection);
 
     sp<InputReporterInterface> mReporter;
+    sp<com::android::internal::compat::IPlatformCompatNative> mCompatService;
 };
 
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index 9154d48..2909d69 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -186,6 +186,13 @@
      * This method may be called on any thread (usually by the input manager).
      */
     virtual status_t pilferPointers(const sp<IBinder>& token) = 0;
+
+    /**
+     * Enables Pointer Capture on the specified window if the window has focus.
+     *
+     * InputDispatcher is the source of truth of Pointer Capture.
+     */
+    virtual void requestPointerCapture(const sp<IBinder>& windowToken, bool enabled) = 0;
 };
 
 } // namespace android
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
index 1125257..c1821ab 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherPolicyInterface.h
@@ -134,6 +134,12 @@
      * The touchedToken passed as an argument is the window that received the input event.
      */
     virtual void onPointerDownOutsideFocus(const sp<IBinder>& touchedToken) = 0;
+
+    /* Change the Pointer Capture state in InputReader.
+     *
+     * InputDispatcher is solely responsible for updating the Pointer Capture state.
+     */
+    virtual void setPointerCapture(bool enabled) = 0;
 };
 
 } // namespace android
diff --git a/services/inputflinger/docs/pointer_capture.md b/services/inputflinger/docs/pointer_capture.md
new file mode 100644
index 0000000..8da699d
--- /dev/null
+++ b/services/inputflinger/docs/pointer_capture.md
@@ -0,0 +1,44 @@
+# Pointer Capture in InputFlinger
+
+## Introduction
+
+[Pointer Capture](https://developer.android.com/training/gestures/movement#pointer-capture) is a feature that was introduced to the Android input pipeline in Android 8.0 (Oreo). Pointer Capture can be enabled or disabled for an `InputWindow` through requests to `InputManagerService`. Enabling Pointer Capture performs the following changes related to the mouse cursor and the devices that control it:
+
+- The position of the mouse cursor is fixed to its location before Pointer Capture was enabled.
+- The mouse cursor is hidden.
+- Events from a mouse will be delivered with the source `SOURCE_MOUSE_RELATIVE`, and their `AXIS_X` and `AXIS_Y` will report relative position changes.
+- Events from a touchpad will be delivered with the source `SOURCE_TOUCHPAD`, and their `AXIS_X` and `AXIS_Y` will report the absolute position of each of the pointers on the touchpad.
+- Events from mouse and touchpad devices are dispatched to the focused `InputWindow`.
+- Events from devices that do not normally control the mouse cursor are not affected.
+
+`InputWindow`s can only gain Pointer Capture if they have window focus. If a window with Pointer Capture loses focus, Pointer Capture is disabled.
+
+## Pointer Capture pipeline in InputFlinger
+
+`InputDispatcher` is responsible for controlling the state of Pointer Capture. Since the feature requires changes to how events are generated, Pointer Capture is configured in `InputReader`.
+
+### Enabling Pointer Capture
+
+There are four key steps that take place when Pointer Capture is enabled:
+
+1. Requests to enable Pointer Capture are forwarded from `InputManagerService` to `InputDispatcher`.
+2. If the window that makes the request has focus, `InputDispatcher` enables the Pointer Capture state in `InputReader` through the `InputDispatcherPolicy`.
+3. When `InputReader` is successfully configured, it notifies `InputDispatcher` through the `InputListener` interface.
+4. `InputDispatcher` then notifies the `InputWindow` that Pointer Capture has been enabled by sending a special `CAPTURE` event through the `InputChannel`.
+
+### Disabling Pointer Capture
+
+Pointer Capture can be disabled in two ways: by a request through `InputManagerService`, and as a result of the `InputWindow` losing focus.
+
+When Pointer Capture is disabled by a request from the application, it follows the same pipeline as when Pointer Capture is enabled.
+
+#### Window loses Pointer Capture when it loses focus
+
+When an `InputWindow` with Pointer Capture loses focus, Pointer Capture is disabled immediately. The `InputWindow` receives a `CAPTURE` event through the `InputChannel`, followed by a `FOCUS` event to notify loss of focus.
+
+## Pointer Capture in `InputDispatcher`
+
+`InputDispatcher` tracks two pieces of state information regarding Pointer Capture:
+
+- `mFocusedWindowRequestedPointerCapture`: Whether or not the focused window has requested Pointer Capture. This is updated whenever the Dispatcher receives requests from `InputManagerService`.
+- `mWindowTokenWithPointerCapture`: The Binder token of the `InputWindow` that currently has Pointer Capture. This is only updated during the dispatch cycle. If it is not `nullptr`, it signifies that the window was notified that it has Pointer Capture.
diff --git a/services/inputflinger/include/InputReaderBase.h b/services/inputflinger/include/InputReaderBase.h
index ffd8bf2..6cce8ec 100644
--- a/services/inputflinger/include/InputReaderBase.h
+++ b/services/inputflinger/include/InputReaderBase.h
@@ -101,10 +101,14 @@
     virtual void requestRefreshConfiguration(uint32_t changes) = 0;
 
     /* Controls the vibrator of a particular input device. */
-    virtual void vibrate(int32_t deviceId, const std::vector<VibrationElement>& pattern,
-                         ssize_t repeat, int32_t token) = 0;
+    virtual void vibrate(int32_t deviceId, const VibrationSequence& sequence, ssize_t repeat,
+                         int32_t token) = 0;
     virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0;
 
+    virtual bool isVibrating(int32_t deviceId) = 0;
+
+    virtual std::vector<int32_t> getVibratorIds(int32_t deviceId) = 0;
+
     /* Return true if the device can send input events to the specified display. */
     virtual bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) = 0;
 };
diff --git a/services/inputflinger/include/VibrationElement.h b/services/inputflinger/include/VibrationElement.h
index b60ffac..736041e 100644
--- a/services/inputflinger/include/VibrationElement.h
+++ b/services/inputflinger/include/VibrationElement.h
@@ -21,6 +21,7 @@
 #include <chrono>
 #include <cstdint>
 #include <string>
+#include <vector>
 
 namespace android {
 
@@ -32,13 +33,43 @@
 struct VibrationElement {
     std::chrono::milliseconds duration;
     // Channel amplitude range 0-255.
-    std::array<uint8_t, CHANNEL_SIZE> channels = {0, 0};
+    std::vector<std::pair<int32_t /*vibratorId*/, uint8_t /*amplitude*/>> channels;
+
+    explicit VibrationElement(size_t channelNum);
+
+    VibrationElement(const VibrationElement& other);
+
+    bool operator==(const VibrationElement& other) const;
+
+    bool operator!=(const VibrationElement& other) const;
+
+    void addChannel(int32_t vibratorId, uint8_t amplitude);
 
     const std::string toString() const;
-    uint16_t getMagnitude(size_t channelIndex) const;
+
+    uint16_t getMagnitude(int32_t vibratorId) const;
+
     bool isOn() const;
 };
 
+/*
+ * Describes a sequence of rumble effect
+ */
+struct VibrationSequence {
+    // Pattern of vibration elements
+    std::vector<VibrationElement> pattern;
+
+    explicit VibrationSequence(size_t length);
+
+    void operator=(const VibrationSequence& other);
+
+    bool operator==(const VibrationSequence& other) const;
+
+    void addElement(VibrationElement element);
+
+    const std::string toString() const;
+};
+
 } // namespace android
 
 #endif // _VIBRATION_ELEMENT_H
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 9671dec..f864c0e 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -61,8 +61,8 @@
 // v4l2 devices go directly into /dev
 static const char* VIDEO_DEVICE_PATH = "/dev";
 
-static constexpr size_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0;
-static constexpr size_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1;
+static constexpr int32_t FF_STRONG_MAGNITUDE_CHANNEL_IDX = 0;
+static constexpr int32_t FF_WEAK_MAGNITUDE_CHANNEL_IDX = 1;
 
 static inline const char* toString(bool value) {
     return value ? "true" : "false";
@@ -475,25 +475,25 @@
 }
 
 InputDeviceIdentifier EventHub::getDeviceIdentifier(int32_t deviceId) const {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     return device != nullptr ? device->identifier : InputDeviceIdentifier();
 }
 
 Flags<InputDeviceClass> EventHub::getDeviceClasses(int32_t deviceId) const {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     return device != nullptr ? device->classes : Flags<InputDeviceClass>(0);
 }
 
 int32_t EventHub::getDeviceControllerNumber(int32_t deviceId) const {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     return device != nullptr ? device->controllerNumber : 0;
 }
 
 void EventHub::getConfiguration(int32_t deviceId, PropertyMap* outConfiguration) const {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     if (device != nullptr && device->configuration) {
         *outConfiguration = *device->configuration;
@@ -507,7 +507,7 @@
     outAxisInfo->clear();
 
     if (axis >= 0 && axis <= ABS_MAX) {
-        std::lock_guard<std::mutex> lock(mLock);
+        std::scoped_lock _l(mLock);
 
         Device* device = getDeviceLocked(deviceId);
         if (device != nullptr && device->hasValidFd() && device->absBitmask.test(axis)) {
@@ -534,7 +534,7 @@
 
 bool EventHub::hasRelativeAxis(int32_t deviceId, int axis) const {
     if (axis >= 0 && axis <= REL_MAX) {
-        std::lock_guard<std::mutex> lock(mLock);
+        std::scoped_lock _l(mLock);
         Device* device = getDeviceLocked(deviceId);
         return device != nullptr ? device->relBitmask.test(axis) : false;
     }
@@ -542,7 +542,7 @@
 }
 
 bool EventHub::hasInputProperty(int32_t deviceId, int property) const {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
 
     Device* device = getDeviceLocked(deviceId);
     return property >= 0 && property <= INPUT_PROP_MAX && device != nullptr
@@ -552,7 +552,7 @@
 
 int32_t EventHub::getScanCodeState(int32_t deviceId, int32_t scanCode) const {
     if (scanCode >= 0 && scanCode <= KEY_MAX) {
-        std::lock_guard<std::mutex> lock(mLock);
+        std::scoped_lock _l(mLock);
 
         Device* device = getDeviceLocked(deviceId);
         if (device != nullptr && device->hasValidFd() && device->keyBitmask.test(scanCode)) {
@@ -565,7 +565,7 @@
 }
 
 int32_t EventHub::getKeyCodeState(int32_t deviceId, int32_t keyCode) const {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
 
     Device* device = getDeviceLocked(deviceId);
     if (device != nullptr && device->hasValidFd() && device->keyMap.haveKeyLayout()) {
@@ -588,7 +588,7 @@
 
 int32_t EventHub::getSwitchState(int32_t deviceId, int32_t sw) const {
     if (sw >= 0 && sw <= SW_MAX) {
-        std::lock_guard<std::mutex> lock(mLock);
+        std::scoped_lock _l(mLock);
 
         Device* device = getDeviceLocked(deviceId);
         if (device != nullptr && device->hasValidFd() && device->swBitmask.test(sw)) {
@@ -604,7 +604,7 @@
     *outValue = 0;
 
     if (axis >= 0 && axis <= ABS_MAX) {
-        std::lock_guard<std::mutex> lock(mLock);
+        std::scoped_lock _l(mLock);
 
         Device* device = getDeviceLocked(deviceId);
         if (device != nullptr && device->hasValidFd() && device->absBitmask.test(axis)) {
@@ -624,7 +624,7 @@
 
 bool EventHub::markSupportedKeyCodes(int32_t deviceId, size_t numCodes, const int32_t* keyCodes,
                                      uint8_t* outFlags) const {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
 
     Device* device = getDeviceLocked(deviceId);
     if (device != nullptr && device->keyMap.haveKeyLayout()) {
@@ -652,7 +652,7 @@
 
 status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode, int32_t metaState,
                           int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     status_t status = NAME_NOT_FOUND;
 
@@ -692,7 +692,7 @@
 }
 
 status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
 
     if (device != nullptr && device->keyMap.haveKeyLayout()) {
@@ -706,13 +706,13 @@
 }
 
 void EventHub::setExcludedDevices(const std::vector<std::string>& devices) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
 
     mExcludedDevices = devices;
 }
 
 bool EventHub::hasScanCode(int32_t deviceId, int32_t scanCode) const {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     if (device != nullptr && scanCode >= 0 && scanCode <= KEY_MAX) {
         return device->keyBitmask.test(scanCode);
@@ -721,7 +721,7 @@
 }
 
 bool EventHub::hasLed(int32_t deviceId, int32_t led) const {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     int32_t sc;
     if (device != nullptr && device->mapLed(led, &sc) == NO_ERROR) {
@@ -731,7 +731,7 @@
 }
 
 void EventHub::setLedState(int32_t deviceId, int32_t led, bool on) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     if (device != nullptr && device->hasValidFd()) {
         device->setLedStateLocked(led, on);
@@ -742,7 +742,7 @@
                                         std::vector<VirtualKeyDefinition>& outVirtualKeys) const {
     outVirtualKeys.clear();
 
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     if (device != nullptr && device->virtualKeyMap) {
         const std::vector<VirtualKeyDefinition> virtualKeys =
@@ -752,7 +752,7 @@
 }
 
 const std::shared_ptr<KeyCharacterMap> EventHub::getKeyCharacterMap(int32_t deviceId) const {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     if (device != nullptr) {
         return device->getKeyCharacterMap();
@@ -761,7 +761,7 @@
 }
 
 bool EventHub::setKeyboardLayoutOverlay(int32_t deviceId, std::shared_ptr<KeyCharacterMap> map) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     if (device != nullptr && map != nullptr && device->keyMap.keyCharacterMap != nullptr) {
         device->keyMap.keyCharacterMap->combine(*map);
@@ -822,7 +822,7 @@
 }
 
 void EventHub::vibrate(int32_t deviceId, const VibrationElement& element) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     if (device != nullptr && device->hasValidFd()) {
         ff_effect effect;
@@ -857,7 +857,7 @@
 }
 
 void EventHub::cancelVibrate(int32_t deviceId) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     if (device != nullptr && device->hasValidFd()) {
         if (device->ffEffectPlaying) {
@@ -878,6 +878,18 @@
     }
 }
 
+std::vector<int32_t> EventHub::getVibratorIds(int32_t deviceId) {
+    std::scoped_lock _l(mLock);
+    std::vector<int32_t> vibrators;
+    Device* device = getDeviceLocked(deviceId);
+    if (device != nullptr && device->hasValidFd() &&
+        device->classes.test(InputDeviceClass::VIBRATOR)) {
+        vibrators.push_back(FF_STRONG_MAGNITUDE_CHANNEL_IDX);
+        vibrators.push_back(FF_WEAK_MAGNITUDE_CHANNEL_IDX);
+    }
+    return vibrators;
+}
+
 EventHub::Device* EventHub::getDeviceByDescriptorLocked(const std::string& descriptor) const {
     for (const auto& [id, device] : mDevices) {
         if (descriptor == device->identifier.descriptor) {
@@ -930,7 +942,7 @@
 size_t EventHub::getEvents(int timeoutMillis, RawEvent* buffer, size_t bufferSize) {
     ALOG_ASSERT(bufferSize >= 1);
 
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
 
     struct input_event readBuffer[bufferSize];
 
@@ -1184,7 +1196,7 @@
 }
 
 std::vector<TouchVideoFrame> EventHub::getVideoFrames(int32_t deviceId) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
 
     Device* device = getDeviceLocked(deviceId);
     if (device == nullptr || !device->videoDevice) {
@@ -1593,7 +1605,7 @@
 }
 
 bool EventHub::isDeviceEnabled(int32_t deviceId) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     if (device == nullptr) {
         ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
@@ -1603,7 +1615,7 @@
 }
 
 status_t EventHub::enableDevice(int32_t deviceId) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     if (device == nullptr) {
         ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
@@ -1625,7 +1637,7 @@
 }
 
 status_t EventHub::disableDevice(int32_t deviceId) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     Device* device = getDeviceLocked(deviceId);
     if (device == nullptr) {
         ALOGE("Invalid device id=%" PRId32 " provided to %s", deviceId, __func__);
@@ -1809,7 +1821,7 @@
 void EventHub::requestReopenDevices() {
     ALOGV("requestReopenDevices() called");
 
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     mNeedToReopenDevices = true;
 }
 
@@ -1817,7 +1829,7 @@
     dump += "Event Hub State:\n";
 
     { // acquire lock
-        std::lock_guard<std::mutex> lock(mLock);
+        std::scoped_lock _l(mLock);
 
         dump += StringPrintf(INDENT "BuiltInKeyboardId: %d\n", mBuiltInKeyboardId);
 
diff --git a/services/inputflinger/reader/InputDevice.cpp b/services/inputflinger/reader/InputDevice.cpp
index 271bc2f..d25d64a 100644
--- a/services/inputflinger/reader/InputDevice.cpp
+++ b/services/inputflinger/reader/InputDevice.cpp
@@ -429,10 +429,9 @@
     return result;
 }
 
-void InputDevice::vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
-                          int32_t token) {
-    for_each_mapper([pattern, repeat, token](InputMapper& mapper) {
-        mapper.vibrate(pattern, repeat, token);
+void InputDevice::vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token) {
+    for_each_mapper([sequence, repeat, token](InputMapper& mapper) {
+        mapper.vibrate(sequence, repeat, token);
     });
 }
 
@@ -440,6 +439,27 @@
     for_each_mapper([token](InputMapper& mapper) { mapper.cancelVibrate(token); });
 }
 
+bool InputDevice::isVibrating() {
+    bool vibrating = false;
+    for_each_mapper([&vibrating](InputMapper& mapper) { vibrating |= mapper.isVibrating(); });
+    return vibrating;
+}
+
+/* There's no guarantee the IDs provided by the different mappers are unique, so if we have two
+ * different vibration mappers then we could have duplicate IDs.
+ * Alternatively, if we have a merged device that has multiple evdev nodes with FF_* capabilities,
+ * we would definitely have duplicate IDs.
+ */
+std::vector<int32_t> InputDevice::getVibratorIds() {
+    std::vector<int32_t> vibrators;
+    for_each_mapper([&vibrators](InputMapper& mapper) {
+        std::vector<int32_t> devVibs = mapper.getVibratorIds();
+        vibrators.reserve(vibrators.size() + devVibs.size());
+        vibrators.insert(vibrators.end(), devVibs.begin(), devVibs.end());
+    });
+    return vibrators;
+}
+
 void InputDevice::cancelTouch(nsecs_t when) {
     for_each_mapper([when](InputMapper& mapper) { mapper.cancelTouch(when); });
 }
diff --git a/services/inputflinger/reader/InputReader.cpp b/services/inputflinger/reader/InputReader.cpp
index 6216d78..a6b5e2d 100644
--- a/services/inputflinger/reader/InputReader.cpp
+++ b/services/inputflinger/reader/InputReader.cpp
@@ -56,7 +56,7 @@
     mQueuedListener = new QueuedInputListener(listener);
 
     { // acquire lock
-        std::lock_guard<std::mutex> lock(mLock);
+        std::scoped_lock _l(mLock);
 
         refreshConfigurationLocked(0);
         updateGlobalMetaStateLocked();
@@ -89,7 +89,7 @@
     bool inputDevicesChanged = false;
     std::vector<InputDeviceInfo> inputDevices;
     { // acquire lock
-        std::lock_guard<std::mutex> lock(mLock);
+        std::scoped_lock _l(mLock);
 
         oldGeneration = mGeneration;
         timeoutMillis = -1;
@@ -108,7 +108,7 @@
     size_t count = mEventHub->getEvents(timeoutMillis, mEventBuffer, EVENT_BUFFER_SIZE);
 
     { // acquire lock
-        std::lock_guard<std::mutex> lock(mLock);
+        std::scoped_lock _l(mLock);
         mReaderIsAliveCondition.notify_all();
 
         if (count) {
@@ -407,7 +407,7 @@
 }
 
 void InputReader::dispatchExternalStylusState(const StylusState& state) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     for (auto& devicePair : mDevices) {
         std::shared_ptr<InputDevice>& device = devicePair.second;
         device->updateExternalStylusState(state);
@@ -482,7 +482,7 @@
 }
 
 std::vector<InputDeviceInfo> InputReader::getInputDevices() const {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     return getInputDevicesLocked();
 }
 
@@ -501,19 +501,19 @@
 }
 
 int32_t InputReader::getKeyCodeState(int32_t deviceId, uint32_t sourceMask, int32_t keyCode) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
 
     return getStateLocked(deviceId, sourceMask, keyCode, &InputDevice::getKeyCodeState);
 }
 
 int32_t InputReader::getScanCodeState(int32_t deviceId, uint32_t sourceMask, int32_t scanCode) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
 
     return getStateLocked(deviceId, sourceMask, scanCode, &InputDevice::getScanCodeState);
 }
 
 int32_t InputReader::getSwitchState(int32_t deviceId, uint32_t sourceMask, int32_t switchCode) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
 
     return getStateLocked(deviceId, sourceMask, switchCode, &InputDevice::getSwitchState);
 }
@@ -545,7 +545,7 @@
 }
 
 void InputReader::toggleCapsLockState(int32_t deviceId) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
     InputDevice* device = findInputDeviceLocked(deviceId);
     if (!device) {
         ALOGW("Ignoring toggleCapsLock for unknown deviceId %" PRId32 ".", deviceId);
@@ -561,7 +561,7 @@
 
 bool InputReader::hasKeys(int32_t deviceId, uint32_t sourceMask, size_t numCodes,
                           const int32_t* keyCodes, uint8_t* outFlags) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
 
     memset(outFlags, 0, numCodes);
     return markSupportedKeyCodesLocked(deviceId, sourceMask, numCodes, keyCodes, outFlags);
@@ -588,7 +588,7 @@
 }
 
 void InputReader::requestRefreshConfiguration(uint32_t changes) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
 
     if (changes) {
         bool needWake = !mConfigurationChangesToRefresh;
@@ -600,17 +600,18 @@
     }
 }
 
-void InputReader::vibrate(int32_t deviceId, const std::vector<VibrationElement>& pattern,
-                          ssize_t repeat, int32_t token) {
-    std::lock_guard<std::mutex> lock(mLock);
+void InputReader::vibrate(int32_t deviceId, const VibrationSequence& sequence, ssize_t repeat,
+                          int32_t token) {
+    std::scoped_lock _l(mLock);
+
     InputDevice* device = findInputDeviceLocked(deviceId);
     if (device) {
-        device->vibrate(pattern, repeat, token);
+        device->vibrate(sequence, repeat, token);
     }
 }
 
 void InputReader::cancelVibrate(int32_t deviceId, int32_t token) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
 
     InputDevice* device = findInputDeviceLocked(deviceId);
     if (device) {
@@ -618,8 +619,28 @@
     }
 }
 
+bool InputReader::isVibrating(int32_t deviceId) {
+    std::scoped_lock _l(mLock);
+
+    InputDevice* device = findInputDeviceLocked(deviceId);
+    if (device) {
+        return device->isVibrating();
+    }
+    return false;
+}
+
+std::vector<int32_t> InputReader::getVibratorIds(int32_t deviceId) {
+    std::scoped_lock _l(mLock);
+
+    InputDevice* device = findInputDeviceLocked(deviceId);
+    if (device) {
+        return device->getVibratorIds();
+    }
+    return {};
+}
+
 bool InputReader::isInputDeviceEnabled(int32_t deviceId) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
 
     InputDevice* device = findInputDeviceLocked(deviceId);
     if (device) {
@@ -630,7 +651,7 @@
 }
 
 bool InputReader::canDispatchToDisplay(int32_t deviceId, int32_t displayId) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
 
     InputDevice* device = findInputDeviceLocked(deviceId);
     if (!device) {
@@ -658,7 +679,7 @@
 }
 
 void InputReader::dump(std::string& dump) {
-    std::lock_guard<std::mutex> lock(mLock);
+    std::scoped_lock _l(mLock);
 
     mEventHub->dump(dump);
     dump += "\n";
diff --git a/services/inputflinger/reader/include/EventHub.h b/services/inputflinger/reader/include/EventHub.h
index a3f881e..9e38d0a 100644
--- a/services/inputflinger/reader/include/EventHub.h
+++ b/services/inputflinger/reader/include/EventHub.h
@@ -233,6 +233,7 @@
     /* Control the vibrator. */
     virtual void vibrate(int32_t deviceId, const VibrationElement& effect) = 0;
     virtual void cancelVibrate(int32_t deviceId) = 0;
+    virtual std::vector<int32_t> getVibratorIds(int32_t deviceId) = 0;
 
     /* Requests the EventHub to reopen all input devices on the next call to getEvents(). */
     virtual void requestReopenDevices() = 0;
@@ -381,6 +382,7 @@
 
     void vibrate(int32_t deviceId, const VibrationElement& effect) override final;
     void cancelVibrate(int32_t deviceId) override final;
+    std::vector<int32_t> getVibratorIds(int32_t deviceId) override final;
 
     void requestReopenDevices() override final;
 
diff --git a/services/inputflinger/reader/include/InputDevice.h b/services/inputflinger/reader/include/InputDevice.h
index 7d160eb..8b14b06 100644
--- a/services/inputflinger/reader/include/InputDevice.h
+++ b/services/inputflinger/reader/include/InputDevice.h
@@ -82,8 +82,10 @@
     int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
     bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes, const int32_t* keyCodes,
                                uint8_t* outFlags);
-    void vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat, int32_t token);
+    void vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token);
     void cancelVibrate(int32_t token);
+    bool isVibrating();
+    std::vector<int32_t> getVibratorIds();
     void cancelTouch(nsecs_t when);
 
     int32_t getMetaState();
@@ -272,6 +274,8 @@
     }
     inline void cancelVibrate() { return mEventHub->cancelVibrate(mId); }
 
+    inline std::vector<int32_t> getVibratorIds() { return mEventHub->getVibratorIds(mId); }
+
     inline bool hasAbsoluteAxis(int32_t code) const {
         RawAbsoluteAxisInfo info;
         mEventHub->getAbsoluteAxisInfo(mId, code, &info);
diff --git a/services/inputflinger/reader/include/InputReader.h b/services/inputflinger/reader/include/InputReader.h
index 9b07681d..b16b86c 100644
--- a/services/inputflinger/reader/include/InputReader.h
+++ b/services/inputflinger/reader/include/InputReader.h
@@ -77,10 +77,14 @@
 
     void requestRefreshConfiguration(uint32_t changes) override;
 
-    void vibrate(int32_t deviceId, const std::vector<VibrationElement>& pattern, ssize_t repeat,
+    void vibrate(int32_t deviceId, const VibrationSequence& sequence, ssize_t repeat,
                  int32_t token) override;
     void cancelVibrate(int32_t deviceId, int32_t token) override;
 
+    bool isVibrating(int32_t deviceId) override;
+
+    std::vector<int32_t> getVibratorIds(int32_t deviceId) override;
+
     bool canDispatchToDisplay(int32_t deviceId, int32_t displayId) override;
 
 protected:
diff --git a/services/inputflinger/reader/mapper/InputMapper.cpp b/services/inputflinger/reader/mapper/InputMapper.cpp
index 1db829f..913cef7 100644
--- a/services/inputflinger/reader/mapper/InputMapper.cpp
+++ b/services/inputflinger/reader/mapper/InputMapper.cpp
@@ -56,11 +56,18 @@
     return false;
 }
 
-void InputMapper::vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
-                          int32_t token) {}
+void InputMapper::vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token) {}
 
 void InputMapper::cancelVibrate(int32_t token) {}
 
+bool InputMapper::isVibrating() {
+    return false;
+}
+
+std::vector<int32_t> InputMapper::getVibratorIds() {
+    return {};
+}
+
 void InputMapper::cancelTouch(nsecs_t when) {}
 
 int32_t InputMapper::getMetaState() {
diff --git a/services/inputflinger/reader/mapper/InputMapper.h b/services/inputflinger/reader/mapper/InputMapper.h
index 56ab928..088dbd8 100644
--- a/services/inputflinger/reader/mapper/InputMapper.h
+++ b/services/inputflinger/reader/mapper/InputMapper.h
@@ -63,9 +63,10 @@
     virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
     virtual bool markSupportedKeyCodes(uint32_t sourceMask, size_t numCodes,
                                        const int32_t* keyCodes, uint8_t* outFlags);
-    virtual void vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
-                         int32_t token);
+    virtual void vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token);
     virtual void cancelVibrate(int32_t token);
+    virtual bool isVibrating();
+    virtual std::vector<int32_t> getVibratorIds();
     virtual void cancelTouch(nsecs_t when);
 
     virtual int32_t getMetaState();
diff --git a/services/inputflinger/reader/mapper/TouchInputMapper.cpp b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
index b620e2d..ce12c27 100644
--- a/services/inputflinger/reader/mapper/TouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/TouchInputMapper.cpp
@@ -647,6 +647,13 @@
         return;
     }
 
+    if (!newViewport->isActive) {
+        ALOGI("Disabling %s (device %i) because the associated viewport is not active",
+              getDeviceName().c_str(), getDeviceId());
+        mDeviceMode = DeviceMode::DISABLED;
+        return;
+    }
+
     // Raw width and height in the natural orientation.
     int32_t rawWidth = mRawPointerAxes.getRawWidth();
     int32_t rawHeight = mRawPointerAxes.getRawHeight();
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
index ac7c266..f25e59a 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.cpp
@@ -21,7 +21,7 @@
 namespace android {
 
 VibratorInputMapper::VibratorInputMapper(InputDeviceContext& deviceContext)
-      : InputMapper(deviceContext), mVibrating(false) {}
+      : InputMapper(deviceContext), mVibrating(false), mSequence(0) {}
 
 VibratorInputMapper::~VibratorInputMapper() {}
 
@@ -39,17 +39,15 @@
     // TODO: Handle FF_STATUS, although it does not seem to be widely supported.
 }
 
-void VibratorInputMapper::vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
+void VibratorInputMapper::vibrate(const VibrationSequence& sequence, ssize_t repeat,
                                   int32_t token) {
 #if DEBUG_VIBRATOR
-    std::string patternStr;
-    dumpPattern(patternStr);
     ALOGD("vibrate: deviceId=%d, pattern=[%s], repeat=%zd, token=%d", getDeviceId(),
-          patternStr.c_str(), repeat, token);
+          sequence.toString().c_str(), repeat, token);
 #endif
 
     mVibrating = true;
-    mPattern = pattern;
+    mSequence = sequence;
     mRepeat = repeat;
     mToken = token;
     mIndex = -1;
@@ -67,6 +65,14 @@
     }
 }
 
+bool VibratorInputMapper::isVibrating() {
+    return mVibrating;
+}
+
+std::vector<int32_t> VibratorInputMapper::getVibratorIds() {
+    return getDeviceContext().getVibratorIds();
+}
+
 void VibratorInputMapper::timeoutExpired(nsecs_t when) {
     if (mVibrating) {
         if (when >= mNextStepTime) {
@@ -79,7 +85,7 @@
 
 void VibratorInputMapper::nextStep() {
     mIndex += 1;
-    if (size_t(mIndex) >= mPattern.size()) {
+    if (size_t(mIndex) >= mSequence.pattern.size()) {
         if (mRepeat < 0) {
             // We are done.
             stopVibrating();
@@ -88,7 +94,7 @@
         mIndex = mRepeat;
     }
 
-    const VibrationElement& element = mPattern[mIndex];
+    const VibrationElement& element = mSequence.pattern[mIndex];
     if (element.isOn()) {
 #if DEBUG_VIBRATOR
         std::string description = element.toString();
@@ -125,23 +131,10 @@
     dump += StringPrintf(INDENT3 "Vibrating: %s\n", toString(mVibrating));
     if (mVibrating) {
         dump += INDENT3 "Pattern: ";
-        dumpPattern(dump);
+        dump += mSequence.toString();
         dump += "\n";
         dump += StringPrintf(INDENT3 "Repeat Index: %zd\n", mRepeat);
     }
 }
 
-void VibratorInputMapper::dumpPattern(std::string& dump) const {
-    dump += "[";
-
-    for (auto it = mPattern.begin(); it != mPattern.end(); ++it) {
-        dump += it->toString();
-        if (std::next(it) != mPattern.end()) {
-            dump += ", ";
-        }
-    }
-
-    dump += "]";
-}
-
 } // namespace android
diff --git a/services/inputflinger/reader/mapper/VibratorInputMapper.h b/services/inputflinger/reader/mapper/VibratorInputMapper.h
index bfa5ec1..7ce621a 100644
--- a/services/inputflinger/reader/mapper/VibratorInputMapper.h
+++ b/services/inputflinger/reader/mapper/VibratorInputMapper.h
@@ -30,21 +30,21 @@
     virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo) override;
     virtual void process(const RawEvent* rawEvent) override;
 
-    virtual void vibrate(const std::vector<VibrationElement>& pattern, ssize_t repeat,
-                         int32_t token) override;
+    virtual void vibrate(const VibrationSequence& sequence, ssize_t repeat, int32_t token) override;
     virtual void cancelVibrate(int32_t token) override;
+    virtual bool isVibrating() override;
+    virtual std::vector<int32_t> getVibratorIds() override;
     virtual void timeoutExpired(nsecs_t when) override;
     virtual void dump(std::string& dump) override;
 
 private:
     bool mVibrating;
-    std::vector<VibrationElement> mPattern;
+    VibrationSequence mSequence;
     ssize_t mRepeat;
     int32_t mToken;
     ssize_t mIndex;
     nsecs_t mNextStepTime;
 
-    void dumpPattern(std::string& dump) const;
     void nextStep();
     void stopVibrating();
 };
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 5ab2ae3..bf05b9f 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -19,10 +19,10 @@
 #include <android-base/stringprintf.h>
 #include <android-base/thread_annotations.h>
 #include <binder/Binder.h>
-#include <input/Input.h>
-
 #include <gtest/gtest.h>
+#include <input/Input.h>
 #include <linux/input.h>
+
 #include <cinttypes>
 #include <thread>
 #include <unordered_set>
@@ -71,12 +71,10 @@
     InputDispatcherConfiguration mConfig;
 
 protected:
-    virtual ~FakeInputDispatcherPolicy() {
-    }
+    virtual ~FakeInputDispatcherPolicy() {}
 
 public:
-    FakeInputDispatcherPolicy() {
-    }
+    FakeInputDispatcherPolicy() {}
 
     void assertFilterInputEventWasCalled(const NotifyKeyArgs& args) {
         assertFilterInputEventWasCalled(AINPUT_EVENT_TYPE_KEY, args.eventTime, args.action,
@@ -211,6 +209,33 @@
         mConfig.keyRepeatDelay = delay;
     }
 
+    void waitForSetPointerCapture(bool enabled) {
+        std::unique_lock lock(mLock);
+        base::ScopedLockAssertion assumeLocked(mLock);
+
+        if (!mPointerCaptureChangedCondition.wait_for(lock, 100ms,
+                                                      [this, enabled]() REQUIRES(mLock) {
+                                                          return mPointerCaptureEnabled &&
+                                                                  *mPointerCaptureEnabled ==
+                                                                  enabled;
+                                                      })) {
+            FAIL() << "Timed out waiting for setPointerCapture(" << enabled << ") to be called.";
+        }
+        mPointerCaptureEnabled.reset();
+    }
+
+    void assertSetPointerCaptureNotCalled() {
+        std::unique_lock lock(mLock);
+        base::ScopedLockAssertion assumeLocked(mLock);
+
+        if (mPointerCaptureChangedCondition.wait_for(lock, 100ms) != std::cv_status::timeout) {
+            FAIL() << "Expected setPointerCapture(enabled) to not be called, but was called. "
+                      "enabled = "
+                   << *mPointerCaptureEnabled;
+        }
+        mPointerCaptureEnabled.reset();
+    }
+
 private:
     std::mutex mLock;
     std::unique_ptr<InputEvent> mFilteredEvent GUARDED_BY(mLock);
@@ -218,6 +243,9 @@
     sp<IBinder> mOnPointerDownToken GUARDED_BY(mLock);
     std::optional<NotifySwitchArgs> mLastNotifySwitch GUARDED_BY(mLock);
 
+    std::condition_variable mPointerCaptureChangedCondition;
+    std::optional<bool> mPointerCaptureEnabled GUARDED_BY(mLock);
+
     // ANR handling
     std::queue<std::shared_ptr<InputApplicationHandle>> mAnrApplications GUARDED_BY(mLock);
     std::queue<sp<IBinder>> mAnrConnectionTokens GUARDED_BY(mLock);
@@ -307,6 +335,12 @@
         mOnPointerDownToken = newToken;
     }
 
+    void setPointerCapture(bool enabled) override {
+        std::scoped_lock lock(mLock);
+        mPointerCaptureEnabled = {enabled};
+        mPointerCaptureChangedCondition.notify_all();
+    }
+
     void assertFilterInputEventWasCalled(int type, nsecs_t eventTime, int32_t action,
                                          int32_t displayId) {
         std::scoped_lock lock(mLock);
@@ -342,7 +376,7 @@
         mFakePolicy = new FakeInputDispatcherPolicy();
         mDispatcher = new InputDispatcher(mFakePolicy);
         mDispatcher->setInputDispatchMode(/*enabled*/ true, /*frozen*/ false);
-        //Start InputDispatcher thread
+        // Start InputDispatcher thread
         ASSERT_EQ(OK, mDispatcher->start());
     }
 
@@ -379,7 +413,6 @@
     }
 };
 
-
 TEST_F(InputDispatcherTest, InjectInputEvent_ValidatesKeyEvents) {
     KeyEvent event;
 
@@ -574,9 +607,7 @@
     }
     virtual ~FakeApplicationHandle() {}
 
-    virtual bool updateInfo() override {
-        return true;
-    }
+    virtual bool updateInfo() override { return true; }
 
     void setDispatchingTimeout(std::chrono::milliseconds timeout) {
         mInfo.dispatchingTimeoutMillis = timeout.count();
@@ -674,6 +705,9 @@
             case AINPUT_EVENT_TYPE_FOCUS: {
                 FAIL() << "Use 'consumeFocusEvent' for FOCUS events";
             }
+            case AINPUT_EVENT_TYPE_CAPTURE: {
+                FAIL() << "Use 'consumeCaptureEvent' for CAPTURE events";
+            }
             default: {
                 FAIL() << mName.c_str() << ": invalid event type: " << expectedEventType;
             }
@@ -696,6 +730,21 @@
         EXPECT_EQ(inTouchMode, focusEvent->getInTouchMode());
     }
 
+    void consumeCaptureEvent(bool hasCapture) {
+        const InputEvent* event = consume();
+        ASSERT_NE(nullptr, event) << mName.c_str()
+                                  << ": consumer should have returned non-NULL event.";
+        ASSERT_EQ(AINPUT_EVENT_TYPE_CAPTURE, event->getType())
+                << "Got " << inputEventTypeToString(event->getType())
+                << " event instead of CAPTURE event";
+
+        ASSERT_EQ(ADISPLAY_ID_NONE, event->getDisplayId())
+                << mName.c_str() << ": event displayId should always be NONE.";
+
+        const auto& captureEvent = static_cast<const CaptureEvent&>(*event);
+        EXPECT_EQ(hasCapture, captureEvent.getPointerCaptureEnabled());
+    }
+
     void assertNoEvents() {
         InputEvent* event = consume();
         if (event == nullptr) {
@@ -713,6 +762,10 @@
             FocusEvent& focusEvent = static_cast<FocusEvent&>(*event);
             ADD_FAILURE() << "Received focus event, hasFocus = "
                           << (focusEvent.getHasFocus() ? "true" : "false");
+        } else if (event->getType() == AINPUT_EVENT_TYPE_CAPTURE) {
+            const auto& captureEvent = static_cast<CaptureEvent&>(*event);
+            ADD_FAILURE() << "Received capture event, pointerCaptureEnabled = "
+                          << (captureEvent.getPointerCaptureEnabled() ? "true" : "false");
         }
         FAIL() << mName.c_str()
                << ": should not have received any events, so consume() should return NULL";
@@ -810,39 +863,40 @@
     }
 
     void consumeMotionCancel(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
-            int32_t expectedFlags = 0) {
+                             int32_t expectedFlags = 0) {
         consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_CANCEL, expectedDisplayId,
                      expectedFlags);
     }
 
     void consumeMotionMove(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
-            int32_t expectedFlags = 0) {
+                           int32_t expectedFlags = 0) {
         consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_MOVE, expectedDisplayId,
                      expectedFlags);
     }
 
     void consumeMotionDown(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
-            int32_t expectedFlags = 0) {
+                           int32_t expectedFlags = 0) {
         consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_DOWN, expectedDisplayId,
                      expectedFlags);
     }
 
     void consumeMotionPointerDown(int32_t pointerIdx,
-            int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT, int32_t expectedFlags = 0) {
-        int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN
-                | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+                                  int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
+                                  int32_t expectedFlags = 0) {
+        int32_t action = AMOTION_EVENT_ACTION_POINTER_DOWN |
+                (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
         consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags);
     }
 
     void consumeMotionPointerUp(int32_t pointerIdx, int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
-            int32_t expectedFlags = 0) {
-        int32_t action = AMOTION_EVENT_ACTION_POINTER_UP
-                | (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
+                                int32_t expectedFlags = 0) {
+        int32_t action = AMOTION_EVENT_ACTION_POINTER_UP |
+                (pointerIdx << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT);
         consumeEvent(AINPUT_EVENT_TYPE_MOTION, action, expectedDisplayId, expectedFlags);
     }
 
     void consumeMotionUp(int32_t expectedDisplayId = ADISPLAY_ID_DEFAULT,
-            int32_t expectedFlags = 0) {
+                         int32_t expectedFlags = 0) {
         consumeEvent(AINPUT_EVENT_TYPE_MOTION, AMOTION_EVENT_ACTION_UP, expectedDisplayId,
                      expectedFlags);
     }
@@ -859,6 +913,12 @@
         mInputReceiver->consumeFocusEvent(hasFocus, inTouchMode);
     }
 
+    void consumeCaptureEvent(bool hasCapture) {
+        ASSERT_NE(mInputReceiver, nullptr)
+                << "Cannot consume events from a window with no receiver";
+        mInputReceiver->consumeCaptureEvent(hasCapture);
+    }
+
     void consumeEvent(int32_t expectedEventType, int32_t expectedAction, int32_t expectedDisplayId,
                       int32_t expectedFlags) {
         ASSERT_NE(mInputReceiver, nullptr) << "Invalid consume event on window with no receiver";
@@ -900,6 +960,11 @@
 
     const std::string& getName() { return mName; }
 
+    void setOwnerInfo(int32_t ownerPid, int32_t ownerUid) {
+        mInfo.ownerPid = ownerPid;
+        mInfo.ownerUid = ownerUid;
+    }
+
 private:
     const std::string mName;
     std::unique_ptr<FakeInputReceiver> mInputReceiver;
@@ -1138,10 +1203,14 @@
     return generateMotionArgs(action, source, displayId, {PointF{100, 200}});
 }
 
+static NotifyPointerCaptureChangedArgs generatePointerCaptureChangedArgs(bool enabled) {
+    return NotifyPointerCaptureChangedArgs(/* id */ 0, systemTime(SYSTEM_TIME_MONOTONIC), enabled);
+}
+
 TEST_F(InputDispatcherTest, SetInputWindow_SingleWindowTouch) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> window = new FakeWindowHandle(application, mDispatcher, "Fake Window",
-            ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> window =
+            new FakeWindowHandle(application, mDispatcher, "Fake Window", ADISPLAY_ID_DEFAULT);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {window}}});
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1204,10 +1273,10 @@
 // The foreground window should receive the first touch down event.
 TEST_F(InputDispatcherTest, SetInputWindow_MultiWindowsTouch) {
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
-    sp<FakeWindowHandle> windowTop = new FakeWindowHandle(application, mDispatcher, "Top",
-            ADISPLAY_ID_DEFAULT);
-    sp<FakeWindowHandle> windowSecond = new FakeWindowHandle(application, mDispatcher, "Second",
-            ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> windowTop =
+            new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> windowSecond =
+            new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
 
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {windowTop, windowSecond}}});
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
@@ -1488,17 +1557,18 @@
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
 
     // Create a couple of windows
-    sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher,
-            "First Window", ADISPLAY_ID_DEFAULT);
-    sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher,
-            "Second Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> firstWindow =
+            new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> secondWindow =
+            new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
 
     // Add the windows to the dispatcher
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
 
     // Send down to the first window
-    NotifyMotionArgs downMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
-            AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT);
+    NotifyMotionArgs downMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT);
     mDispatcher->notifyMotion(&downMotionArgs);
     // Only the first window should get the down event
     firstWindow->consumeMotionDown();
@@ -1511,8 +1581,9 @@
     secondWindow->consumeMotionDown();
 
     // Send up event to the second window
-    NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP,
-            AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT);
+    NotifyMotionArgs upMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT);
     mDispatcher->notifyMotion(&upMotionArgs);
     // The first  window gets no events and the second gets up
     firstWindow->assertNoEvents();
@@ -1525,26 +1596,29 @@
     PointF touchPoint = {10, 10};
 
     // Create a couple of windows
-    sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher,
-            "First Window", ADISPLAY_ID_DEFAULT);
-    sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher,
-            "Second Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> firstWindow =
+            new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> secondWindow =
+            new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
 
     // Add the windows to the dispatcher
     mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {firstWindow, secondWindow}}});
 
     // Send down to the first window
-    NotifyMotionArgs downMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
-            AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint});
+    NotifyMotionArgs downMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT, {touchPoint});
     mDispatcher->notifyMotion(&downMotionArgs);
     // Only the first window should get the down event
     firstWindow->consumeMotionDown();
     secondWindow->assertNoEvents();
 
     // Send pointer down to the first window
-    NotifyMotionArgs pointerDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN
-            | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint});
+    NotifyMotionArgs pointerDownMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN |
+                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+                               AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {touchPoint, touchPoint});
     mDispatcher->notifyMotion(&pointerDownMotionArgs);
     // Only the first window should get the pointer down event
     firstWindow->consumeMotionPointerDown(1);
@@ -1558,17 +1632,20 @@
     secondWindow->consumeMotionPointerDown(1);
 
     // Send pointer up to the second window
-    NotifyMotionArgs pointerUpMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP
-            | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {touchPoint, touchPoint});
+    NotifyMotionArgs pointerUpMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP |
+                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+                               AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {touchPoint, touchPoint});
     mDispatcher->notifyMotion(&pointerUpMotionArgs);
     // The first window gets nothing and the second gets pointer up
     firstWindow->assertNoEvents();
     secondWindow->consumeMotionPointerUp(1);
 
     // Send up event to the second window
-    NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP,
-            AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT);
+    NotifyMotionArgs upMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT);
     mDispatcher->notifyMotion(&upMotionArgs);
     // The first window gets nothing and the second gets up
     firstWindow->assertNoEvents();
@@ -1579,15 +1656,15 @@
     std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
 
     // Create a non touch modal window that supports split touch
-    sp<FakeWindowHandle> firstWindow = new FakeWindowHandle(application, mDispatcher,
-            "First Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> firstWindow =
+            new FakeWindowHandle(application, mDispatcher, "First Window", ADISPLAY_ID_DEFAULT);
     firstWindow->setFrame(Rect(0, 0, 600, 400));
     firstWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
                           InputWindowInfo::Flag::SPLIT_TOUCH);
 
     // Create a non touch modal window that supports split touch
-    sp<FakeWindowHandle> secondWindow = new FakeWindowHandle(application, mDispatcher,
-            "Second Window", ADISPLAY_ID_DEFAULT);
+    sp<FakeWindowHandle> secondWindow =
+            new FakeWindowHandle(application, mDispatcher, "Second Window", ADISPLAY_ID_DEFAULT);
     secondWindow->setFrame(Rect(0, 400, 600, 800));
     secondWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
                            InputWindowInfo::Flag::SPLIT_TOUCH);
@@ -1599,17 +1676,20 @@
     PointF pointInSecond = {300, 600};
 
     // Send down to the first window
-    NotifyMotionArgs firstDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN,
-            AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst});
+    NotifyMotionArgs firstDownMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT, {pointInFirst});
     mDispatcher->notifyMotion(&firstDownMotionArgs);
     // Only the first window should get the down event
     firstWindow->consumeMotionDown();
     secondWindow->assertNoEvents();
 
     // Send down to the second window
-    NotifyMotionArgs secondDownMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN
-            | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond});
+    NotifyMotionArgs secondDownMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_DOWN |
+                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+                               AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {pointInFirst, pointInSecond});
     mDispatcher->notifyMotion(&secondDownMotionArgs);
     // The first window gets a move and the second a down
     firstWindow->consumeMotionMove();
@@ -1622,17 +1702,20 @@
     secondWindow->consumeMotionPointerDown(1);
 
     // Send pointer up to the second window
-    NotifyMotionArgs pointerUpMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP
-            | (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
-            AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {pointInFirst, pointInSecond});
+    NotifyMotionArgs pointerUpMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_POINTER_UP |
+                                       (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
+                               AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {pointInFirst, pointInSecond});
     mDispatcher->notifyMotion(&pointerUpMotionArgs);
     // The first window gets nothing and the second gets pointer up
     firstWindow->assertNoEvents();
     secondWindow->consumeMotionPointerUp(1);
 
     // Send up event to the second window
-    NotifyMotionArgs upMotionArgs = generateMotionArgs(AMOTION_EVENT_ACTION_UP,
-            AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT);
+    NotifyMotionArgs upMotionArgs =
+            generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN,
+                               ADISPLAY_ID_DEFAULT);
     mDispatcher->notifyMotion(&upMotionArgs);
     // The first window gets nothing and the second gets up
     firstWindow->assertNoEvents();
@@ -2161,6 +2244,72 @@
     window->consumeKeyDown(ADISPLAY_ID_DEFAULT);
 }
 
+/**
+ * Launch two windows, with different owners. One window (slipperyExitWindow) has Flag::SLIPPERY,
+ * and overlaps the other window, slipperyEnterWindow. The window 'slipperyExitWindow' is on top
+ * of the 'slipperyEnterWindow'.
+ *
+ * Inject touch down into the top window. Upon receipt of the DOWN event, move the window in such
+ * a way so that the touched location is no longer covered by the top window.
+ *
+ * Next, inject a MOVE event. Because the top window already moved earlier, this event is now
+ * positioned over the bottom (slipperyEnterWindow) only. And because the top window had
+ * Flag::SLIPPERY, this will cause the top window to lose the touch event (it will receive
+ * ACTION_CANCEL instead), and the bottom window will receive a newly generated gesture (starting
+ * with ACTION_DOWN).
+ * Thus, the touch has been transferred from the top window into the bottom window, because the top
+ * window moved itself away from the touched location and had Flag::SLIPPERY.
+ *
+ * Even though the top window moved away from the touched location, it is still obscuring the bottom
+ * window. It's just not obscuring it at the touched location. That means, FLAG_WINDOW_IS_PARTIALLY_
+ * OBSCURED should be set for the MotionEvent that reaches the bottom window.
+ *
+ * In this test, we ensure that the event received by the bottom window has
+ * FLAG_WINDOW_IS_PARTIALLY_OBSCURED.
+ */
+TEST_F(InputDispatcherTest, SlipperyWindow_SetsFlagPartiallyObscured) {
+    constexpr int32_t SLIPPERY_PID = INJECTOR_PID + 1;
+    constexpr int32_t SLIPPERY_UID = INJECTOR_UID + 1;
+
+    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+    mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application);
+
+    sp<FakeWindowHandle> slipperyExitWindow =
+            new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
+    slipperyExitWindow->setFlags(InputWindowInfo::Flag::NOT_TOUCH_MODAL |
+                                 InputWindowInfo::Flag::SLIPPERY);
+    // Make sure this one overlaps the bottom window
+    slipperyExitWindow->setFrame(Rect(25, 25, 75, 75));
+    // Change the owner uid/pid of the window so that it is considered to be occluding the bottom
+    // one. Windows with the same owner are not considered to be occluding each other.
+    slipperyExitWindow->setOwnerInfo(SLIPPERY_PID, SLIPPERY_UID);
+
+    sp<FakeWindowHandle> slipperyEnterWindow =
+            new FakeWindowHandle(application, mDispatcher, "Second", ADISPLAY_ID_DEFAULT);
+    slipperyExitWindow->setFrame(Rect(0, 0, 100, 100));
+
+    mDispatcher->setInputWindows(
+            {{ADISPLAY_ID_DEFAULT, {slipperyExitWindow, slipperyEnterWindow}}});
+
+    // Use notifyMotion instead of injecting to avoid dealing with injection permissions
+    NotifyMotionArgs args = generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN,
+                                               ADISPLAY_ID_DEFAULT, {{50, 50}});
+    mDispatcher->notifyMotion(&args);
+    slipperyExitWindow->consumeMotionDown();
+    slipperyExitWindow->setFrame(Rect(70, 70, 100, 100));
+    mDispatcher->setInputWindows(
+            {{ADISPLAY_ID_DEFAULT, {slipperyExitWindow, slipperyEnterWindow}}});
+
+    args = generateMotionArgs(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN,
+                              ADISPLAY_ID_DEFAULT, {{51, 51}});
+    mDispatcher->notifyMotion(&args);
+
+    slipperyExitWindow->consumeMotionCancel();
+
+    slipperyEnterWindow->consumeMotionDown(ADISPLAY_ID_DEFAULT,
+                                           AMOTION_EVENT_FLAG_WINDOW_IS_PARTIALLY_OBSCURED);
+}
+
 class InputDispatcherKeyRepeatTest : public InputDispatcherTest {
 protected:
     static constexpr nsecs_t KEY_REPEAT_TIMEOUT = 40 * 1000000; // 40 ms
@@ -2308,8 +2457,8 @@
         InputDispatcherTest::SetUp();
 
         application1 = std::make_shared<FakeApplicationHandle>();
-        windowInPrimary = new FakeWindowHandle(application1, mDispatcher, "D_1",
-                ADISPLAY_ID_DEFAULT);
+        windowInPrimary =
+                new FakeWindowHandle(application1, mDispatcher, "D_1", ADISPLAY_ID_DEFAULT);
 
         // Set focus window for primary display, but focused display would be second one.
         mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, application1);
@@ -2319,8 +2468,8 @@
         windowInPrimary->consumeFocusEvent(true);
 
         application2 = std::make_shared<FakeApplicationHandle>();
-        windowInSecondary = new FakeWindowHandle(application2, mDispatcher, "D_2",
-                SECOND_DISPLAY_ID);
+        windowInSecondary =
+                new FakeWindowHandle(application2, mDispatcher, "D_2", SECOND_DISPLAY_ID);
         // Set focus to second display window.
         // Set focus display to second one.
         mDispatcher->setFocusedDisplay(SECOND_DISPLAY_ID);
@@ -2431,7 +2580,7 @@
 
 // Test per-display input monitors for key event.
 TEST_F(InputDispatcherFocusOnTwoDisplaysTest, MonitorKeyEvent_MultiDisplay) {
-    //Input monitor per display.
+    // Input monitor per display.
     FakeMonitorReceiver monitorInPrimary =
             FakeMonitorReceiver(mDispatcher, "M_1", ADISPLAY_ID_DEFAULT);
     FakeMonitorReceiver monitorInSecondary =
@@ -2470,11 +2619,11 @@
     void testNotifyMotion(int32_t displayId, bool expectToBeFiltered) {
         NotifyMotionArgs motionArgs;
 
-        motionArgs = generateMotionArgs(
-                AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId);
+        motionArgs =
+                generateMotionArgs(AMOTION_EVENT_ACTION_DOWN, AINPUT_SOURCE_TOUCHSCREEN, displayId);
         mDispatcher->notifyMotion(&motionArgs);
-        motionArgs = generateMotionArgs(
-                AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId);
+        motionArgs =
+                generateMotionArgs(AMOTION_EVENT_ACTION_UP, AINPUT_SOURCE_TOUCHSCREEN, displayId);
         mDispatcher->notifyMotion(&motionArgs);
         ASSERT_TRUE(mDispatcher->waitForIdle());
         if (expectToBeFiltered) {
@@ -2542,8 +2691,8 @@
 
         std::shared_ptr<FakeApplicationHandle> application =
                 std::make_shared<FakeApplicationHandle>();
-        mUnfocusedWindow = new FakeWindowHandle(application, mDispatcher, "Top",
-                ADISPLAY_ID_DEFAULT);
+        mUnfocusedWindow =
+                new FakeWindowHandle(application, mDispatcher, "Top", ADISPLAY_ID_DEFAULT);
         mUnfocusedWindow->setFrame(Rect(0, 0, 30, 30));
         // Adding FLAG_NOT_TOUCH_MODAL to ensure taps outside this window are not sent to this
         // window.
@@ -2618,8 +2767,7 @@
 // Have two windows, one with focus. Inject MotionEvent with source TOUCHSCREEN and action
 // DOWN on the window that already has focus. Ensure no window received the
 // onPointerDownOutsideFocus callback.
-TEST_F(InputDispatcherOnPointerDownOutsideFocus,
-        OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
+TEST_F(InputDispatcherOnPointerDownOutsideFocus, OnPointerDownOutsideFocus_OnAlreadyFocusedWindow) {
     ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
               injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
                                FOCUSED_WINDOW_TOUCH_POINT))
@@ -3824,4 +3972,88 @@
     // window gets the pending key event
     mWindow->consumeKeyDown(ADISPLAY_ID_DEFAULT);
 }
+
+class InputDispatcherPointerCaptureTests : public InputDispatcherTest {
+protected:
+    std::shared_ptr<FakeApplicationHandle> mApp;
+    sp<FakeWindowHandle> mWindow;
+    sp<FakeWindowHandle> mSecondWindow;
+
+    void SetUp() override {
+        InputDispatcherTest::SetUp();
+        mApp = std::make_shared<FakeApplicationHandle>();
+        mWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow", ADISPLAY_ID_DEFAULT);
+        mWindow->setFocusable(true);
+        mSecondWindow = new FakeWindowHandle(mApp, mDispatcher, "TestWindow2", ADISPLAY_ID_DEFAULT);
+        mSecondWindow->setFocusable(true);
+
+        mDispatcher->setFocusedApplication(ADISPLAY_ID_DEFAULT, mApp);
+        mDispatcher->setInputWindows({{ADISPLAY_ID_DEFAULT, {mWindow, mSecondWindow}}});
+
+        setFocusedWindow(mWindow);
+        mWindow->consumeFocusEvent(true);
+    }
+
+    void notifyPointerCaptureChanged(bool enabled) {
+        const NotifyPointerCaptureChangedArgs args = generatePointerCaptureChangedArgs(enabled);
+        mDispatcher->notifyPointerCaptureChanged(&args);
+    }
+
+    void requestAndVerifyPointerCapture(const sp<FakeWindowHandle>& window, bool enabled) {
+        mDispatcher->requestPointerCapture(window->getToken(), enabled);
+        mFakePolicy->waitForSetPointerCapture(enabled);
+        notifyPointerCaptureChanged(enabled);
+        window->consumeCaptureEvent(enabled);
+    }
+};
+
+TEST_F(InputDispatcherPointerCaptureTests, EnablePointerCaptureWhenFocused) {
+    // Ensure that capture cannot be obtained for unfocused windows.
+    mDispatcher->requestPointerCapture(mSecondWindow->getToken(), true);
+    mFakePolicy->assertSetPointerCaptureNotCalled();
+    mSecondWindow->assertNoEvents();
+
+    // Ensure that capture can be enabled from the focus window.
+    requestAndVerifyPointerCapture(mWindow, true);
+
+    // Ensure that capture cannot be disabled from a window that does not have capture.
+    mDispatcher->requestPointerCapture(mSecondWindow->getToken(), false);
+    mFakePolicy->assertSetPointerCaptureNotCalled();
+
+    // Ensure that capture can be disabled from the window with capture.
+    requestAndVerifyPointerCapture(mWindow, false);
+}
+
+TEST_F(InputDispatcherPointerCaptureTests, DisablesPointerCaptureAfterWindowLosesFocus) {
+    requestAndVerifyPointerCapture(mWindow, true);
+
+    setFocusedWindow(mSecondWindow);
+
+    // Ensure that the capture disabled event was sent first.
+    mWindow->consumeCaptureEvent(false);
+    mWindow->consumeFocusEvent(false);
+    mSecondWindow->consumeFocusEvent(true);
+    mFakePolicy->waitForSetPointerCapture(false);
+
+    // Ensure that additional state changes from InputReader are not sent to the window.
+    notifyPointerCaptureChanged(false);
+    notifyPointerCaptureChanged(true);
+    notifyPointerCaptureChanged(false);
+    mWindow->assertNoEvents();
+    mSecondWindow->assertNoEvents();
+    mFakePolicy->assertSetPointerCaptureNotCalled();
+}
+
+TEST_F(InputDispatcherPointerCaptureTests, UnexpectedStateChangeDisablesPointerCapture) {
+    requestAndVerifyPointerCapture(mWindow, true);
+
+    // InputReader unexpectedly disables and enables pointer capture.
+    notifyPointerCaptureChanged(false);
+    notifyPointerCaptureChanged(true);
+
+    // Ensure that Pointer Capture is disabled.
+    mWindow->consumeCaptureEvent(false);
+    mWindow->assertNoEvents();
+}
+
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index 5a4c881..c26a389 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -27,6 +27,7 @@
 #include <TestInputListener.h>
 #include <TouchInputMapper.h>
 #include <UinputDevice.h>
+#include <VibratorInputMapper.h>
 #include <android-base/thread_annotations.h>
 #include <gtest/gtest.h>
 #include <inttypes.h>
@@ -223,10 +224,11 @@
     }
 
     void addDisplayViewport(int32_t displayId, int32_t width, int32_t height, int32_t orientation,
-            const std::string& uniqueId, std::optional<uint8_t> physicalPort,
-            ViewportType viewportType) {
-        const DisplayViewport viewport = createDisplayViewport(displayId, width, height,
-                orientation, uniqueId, physicalPort, viewportType);
+                            bool isActive, const std::string& uniqueId,
+                            std::optional<uint8_t> physicalPort, ViewportType viewportType) {
+        const DisplayViewport viewport =
+                createDisplayViewport(displayId, width, height, orientation, isActive, uniqueId,
+                                      physicalPort, viewportType);
         mViewports.push_back(viewport);
         mConfig.setDisplayViewports(mViewports);
     }
@@ -294,8 +296,9 @@
 
 private:
     DisplayViewport createDisplayViewport(int32_t displayId, int32_t width, int32_t height,
-            int32_t orientation, const std::string& uniqueId, std::optional<uint8_t> physicalPort,
-            ViewportType type) {
+                                          int32_t orientation, bool isActive,
+                                          const std::string& uniqueId,
+                                          std::optional<uint8_t> physicalPort, ViewportType type) {
         bool isRotated = (orientation == DISPLAY_ORIENTATION_90
                 || orientation == DISPLAY_ORIENTATION_270);
         DisplayViewport v;
@@ -311,6 +314,7 @@
         v.physicalBottom = isRotated ? width : height;
         v.deviceWidth = isRotated ? height : width;
         v.deviceHeight = isRotated ? width : height;
+        v.isActive = isActive;
         v.uniqueId = uniqueId;
         v.physicalPort = physicalPort;
         v.type = type;
@@ -396,6 +400,7 @@
     std::vector<std::string> mExcludedDevices;
     List<RawEvent> mEvents GUARDED_BY(mLock);
     std::unordered_map<int32_t /*deviceId*/, std::vector<TouchVideoFrame>> mVideoFrames;
+    std::vector<int32_t> mVibrators = {0, 1};
 
 public:
     virtual ~FakeEventHub() {
@@ -810,6 +815,8 @@
 
     void cancelVibrate(int32_t) override {}
 
+    std::vector<int32_t> getVibratorIds(int32_t deviceId) override { return mVibrators; };
+
     virtual bool isExternal(int32_t) const {
         return false;
     }
@@ -1113,7 +1120,7 @@
 
     // Add an internal viewport, then clear it
     mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                                    DISPLAY_ORIENTATION_0, uniqueId, NO_PORT,
+                                    DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId, NO_PORT,
                                     ViewportType::INTERNAL);
 
     // Check matching by uniqueId
@@ -1144,20 +1151,20 @@
 
     // Add an internal viewport
     mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                                    DISPLAY_ORIENTATION_0, internalUniqueId, NO_PORT,
-                                    ViewportType::INTERNAL);
+                                    DISPLAY_ORIENTATION_0, true /*isActive*/, internalUniqueId,
+                                    NO_PORT, ViewportType::INTERNAL);
     // Add an external viewport
     mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                                    DISPLAY_ORIENTATION_0, externalUniqueId, NO_PORT,
-                                    ViewportType::EXTERNAL);
+                                    DISPLAY_ORIENTATION_0, true /*isActive*/, externalUniqueId,
+                                    NO_PORT, ViewportType::EXTERNAL);
     // Add an virtual viewport
     mFakePolicy->addDisplayViewport(virtualDisplayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                                    DISPLAY_ORIENTATION_0, virtualUniqueId1, NO_PORT,
-                                    ViewportType::VIRTUAL);
+                                    DISPLAY_ORIENTATION_0, true /*isActive*/, virtualUniqueId1,
+                                    NO_PORT, ViewportType::VIRTUAL);
     // Add another virtual viewport
     mFakePolicy->addDisplayViewport(virtualDisplayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                                    DISPLAY_ORIENTATION_0, virtualUniqueId2, NO_PORT,
-                                    ViewportType::VIRTUAL);
+                                    DISPLAY_ORIENTATION_0, true /*isActive*/, virtualUniqueId2,
+                                    NO_PORT, ViewportType::VIRTUAL);
 
     // Check matching by type for internal
     std::optional<DisplayViewport> internalViewport =
@@ -1206,10 +1213,12 @@
         mFakePolicy->clearViewports();
         // Add a viewport
         mFakePolicy->addDisplayViewport(displayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_0, uniqueId1, NO_PORT, type);
+                                        DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId1,
+                                        NO_PORT, type);
         // Add another viewport
         mFakePolicy->addDisplayViewport(displayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_0, uniqueId2, NO_PORT, type);
+                                        DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId2,
+                                        NO_PORT, type);
 
         // Check that correct display viewport was returned by comparing the display IDs.
         std::optional<DisplayViewport> viewport1 =
@@ -1249,10 +1258,10 @@
     // Add the default display first and ensure it gets returned.
     mFakePolicy->clearViewports();
     mFakePolicy->addDisplayViewport(ADISPLAY_ID_DEFAULT, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                                    DISPLAY_ORIENTATION_0, uniqueId1, NO_PORT,
+                                    DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId1, NO_PORT,
                                     ViewportType::INTERNAL);
     mFakePolicy->addDisplayViewport(nonDefaultDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                                    DISPLAY_ORIENTATION_0, uniqueId2, NO_PORT,
+                                    DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId2, NO_PORT,
                                     ViewportType::INTERNAL);
 
     std::optional<DisplayViewport> viewport =
@@ -1264,10 +1273,10 @@
     // Add the default display second to make sure order doesn't matter.
     mFakePolicy->clearViewports();
     mFakePolicy->addDisplayViewport(nonDefaultDisplayId, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                                    DISPLAY_ORIENTATION_0, uniqueId2, NO_PORT,
+                                    DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId2, NO_PORT,
                                     ViewportType::INTERNAL);
     mFakePolicy->addDisplayViewport(ADISPLAY_ID_DEFAULT, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                                    DISPLAY_ORIENTATION_0, uniqueId1, NO_PORT,
+                                    DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId1, NO_PORT,
                                     ViewportType::INTERNAL);
 
     viewport = mFakePolicy->getDisplayViewportByType(ViewportType::INTERNAL);
@@ -1292,10 +1301,12 @@
     mFakePolicy->clearViewports();
     // Add a viewport that's associated with some display port that's not of interest.
     mFakePolicy->addDisplayViewport(displayId1, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_0, uniqueId1, hdmi3, type);
+                                    DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId1, hdmi3,
+                                    type);
     // Add another viewport, connected to HDMI1 port
     mFakePolicy->addDisplayViewport(displayId2, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-            DISPLAY_ORIENTATION_0, uniqueId2, hdmi1, type);
+                                    DISPLAY_ORIENTATION_0, true /*isActive*/, uniqueId2, hdmi1,
+                                    type);
 
     // Check that correct display viewport was returned by comparing the display ports.
     std::optional<DisplayViewport> hdmi1Viewport = mFakePolicy->getDisplayViewportByPort(hdmi1);
@@ -1699,10 +1710,10 @@
     // Add default and second display.
     mFakePolicy->clearViewports();
     mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                                    DISPLAY_ORIENTATION_0, "local:0", NO_PORT,
+                                    DISPLAY_ORIENTATION_0, true /*isActive*/, "local:0", NO_PORT,
                                     ViewportType::INTERNAL);
     mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                                    DISPLAY_ORIENTATION_0, "local:1", hdmi1,
+                                    DISPLAY_ORIENTATION_0, true /*isActive*/, "local:1", hdmi1,
                                     ViewportType::EXTERNAL);
     mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
     mReader->loopOnce();
@@ -1816,6 +1827,31 @@
     ASSERT_FALSE(args.enabled) << "Pointer Capture should be disabled.";
 }
 
+class FakeVibratorInputMapper : public FakeInputMapper {
+public:
+    FakeVibratorInputMapper(InputDeviceContext& deviceContext, uint32_t sources)
+          : FakeInputMapper(deviceContext, sources) {}
+
+    std::vector<int32_t> getVibratorIds() override { return getDeviceContext().getVibratorIds(); }
+};
+
+TEST_F(InputReaderTest, VibratorGetVibratorIds) {
+    constexpr int32_t deviceId = END_RESERVED_ID + 1000;
+    Flags<InputDeviceClass> deviceClass = InputDeviceClass::KEYBOARD | InputDeviceClass::VIBRATOR;
+    constexpr int32_t eventHubId = 1;
+    const char* DEVICE_LOCATION = "BLUETOOTH";
+    std::shared_ptr<InputDevice> device = mReader->newDevice(deviceId, "fake", DEVICE_LOCATION);
+    FakeVibratorInputMapper& mapper =
+            device->addMapper<FakeVibratorInputMapper>(eventHubId, AINPUT_SOURCE_KEYBOARD);
+    mReader->pushNextDevice(device);
+
+    ASSERT_NO_FATAL_FAILURE(addDevice(eventHubId, "fake", deviceClass, nullptr));
+    ASSERT_NO_FATAL_FAILURE(mapper.assertConfigureWasCalled());
+
+    ASSERT_EQ(mapper.getVibratorIds().size(), 2U);
+    ASSERT_EQ(mReader->getVibratorIds(deviceId).size(), 2U);
+}
+
 // --- InputReaderIntegrationTest ---
 
 // These tests create and interact with the InputReader only through its interface.
@@ -1971,8 +2007,8 @@
                                       int32_t orientation, const std::string& uniqueId,
                                       std::optional<uint8_t> physicalPort,
                                       ViewportType viewportType) {
-        mFakePolicy->addDisplayViewport(displayId, width, height, orientation, uniqueId,
-                                        physicalPort, viewportType);
+        mFakePolicy->addDisplayViewport(displayId, width, height, orientation, true /*isActive*/,
+                                        uniqueId, physicalPort, viewportType);
         mReader->requestRefreshConfiguration(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
     }
 
@@ -2302,7 +2338,8 @@
 
     // Prepare displays.
     mFakePolicy->addDisplayViewport(SECONDARY_DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
-                                    DISPLAY_ORIENTATION_0, UNIQUE_ID, hdmi, ViewportType::INTERNAL);
+                                    DISPLAY_ORIENTATION_0, true /*isActive*/, UNIQUE_ID, hdmi,
+                                    ViewportType::INTERNAL);
     mDevice->configure(ARBITRARY_TIME, mFakePolicy->getReaderConfiguration(),
                        InputReaderConfiguration::CHANGE_DISPLAY_INFO);
     ASSERT_TRUE(mDevice->isEnabled());
@@ -2392,8 +2429,8 @@
     void setDisplayInfoAndReconfigure(int32_t displayId, int32_t width, int32_t height,
             int32_t orientation, const std::string& uniqueId,
             std::optional<uint8_t> physicalPort, ViewportType viewportType) {
-        mFakePolicy->addDisplayViewport(
-                displayId, width, height, orientation, uniqueId, physicalPort, viewportType);
+        mFakePolicy->addDisplayViewport(displayId, width, height, orientation, true /*isActive*/,
+                                        uniqueId, physicalPort, viewportType);
         configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
     }
 
@@ -2496,6 +2533,46 @@
     ASSERT_EQ(uint32_t(0), args.policyFlags);
 }
 
+// --- VibratorInputMapperTest ---
+class VibratorInputMapperTest : public InputMapperTest {
+protected:
+    void SetUp() override { InputMapperTest::SetUp(DEVICE_CLASSES | InputDeviceClass::VIBRATOR); }
+};
+
+TEST_F(VibratorInputMapperTest, GetSources) {
+    VibratorInputMapper& mapper = addMapperAndConfigure<VibratorInputMapper>();
+
+    ASSERT_EQ(AINPUT_SOURCE_UNKNOWN, mapper.getSources());
+}
+
+TEST_F(VibratorInputMapperTest, GetVibratorIds) {
+    VibratorInputMapper& mapper = addMapperAndConfigure<VibratorInputMapper>();
+
+    ASSERT_EQ(mapper.getVibratorIds().size(), 2U);
+}
+
+TEST_F(VibratorInputMapperTest, Vibrate) {
+    constexpr uint8_t DEFAULT_AMPLITUDE = 192;
+    VibratorInputMapper& mapper = addMapperAndConfigure<VibratorInputMapper>();
+
+    VibrationElement pattern(2);
+    VibrationSequence sequence(2);
+    pattern.duration = std::chrono::milliseconds(200);
+    pattern.channels = {{0 /* vibratorId */, DEFAULT_AMPLITUDE / 2},
+                        {1 /* vibratorId */, DEFAULT_AMPLITUDE}};
+    sequence.addElement(pattern);
+    pattern.duration = std::chrono::milliseconds(500);
+    pattern.channels = {{0 /* vibratorId */, DEFAULT_AMPLITUDE / 4},
+                        {1 /* vibratorId */, DEFAULT_AMPLITUDE}};
+    sequence.addElement(pattern);
+
+    std::vector<int64_t> timings = {0, 1};
+    std::vector<uint8_t> amplitudes = {DEFAULT_AMPLITUDE, DEFAULT_AMPLITUDE / 2};
+
+    ASSERT_FALSE(mapper.isVibrating());
+    mapper.vibrate(sequence, -1 /* repeat */, 0 /* token */);
+    ASSERT_TRUE(mapper.isVibrating());
+}
 
 // --- KeyboardInputMapperTest ---
 
@@ -3988,7 +4065,8 @@
     constexpr int32_t SECOND_DISPLAY_ID = 1;
     const std::string SECOND_DISPLAY_UNIQUE_ID = "local:1";
     mFakePolicy->addDisplayViewport(SECOND_DISPLAY_ID, 800, 480, DISPLAY_ORIENTATION_0,
-                                    SECOND_DISPLAY_UNIQUE_ID, NO_PORT, ViewportType::EXTERNAL);
+                                    true /*isActive*/, SECOND_DISPLAY_UNIQUE_ID, NO_PORT,
+                                    ViewportType::EXTERNAL);
     mFakePolicy->setDefaultPointerDisplayId(SECOND_DISPLAY_ID);
     configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
 
@@ -7039,6 +7117,26 @@
     ASSERT_EQ(SECONDARY_DISPLAY_ID, motionArgs.displayId);
 }
 
+/**
+ * When the viewport is not active (isActive=false), the touch mapper should be disabled and the
+ * events should not be delivered to the listener.
+ */
+TEST_F(MultiTouchInputMapperTest, WhenViewportIsNotActive_TouchesAreDropped) {
+    addConfigurationProperty("touch.deviceType", "touchScreen");
+    mFakePolicy->addDisplayViewport(DISPLAY_ID, DISPLAY_WIDTH, DISPLAY_HEIGHT,
+                                    DISPLAY_ORIENTATION_0, false /*isActive*/, UNIQUE_ID, NO_PORT,
+                                    ViewportType::INTERNAL);
+    configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
+    prepareAxes(POSITION);
+    MultiTouchInputMapper& mapper = addMapperAndConfigure<MultiTouchInputMapper>();
+
+    NotifyMotionArgs motionArgs;
+    processPosition(mapper, 100, 100);
+    processSync(mapper);
+
+    mFakeListener->assertNotifyMotionWasNotCalled();
+}
+
 TEST_F(MultiTouchInputMapperTest, Process_Pointer_ShowTouches) {
     // Setup the first touch screen device.
     prepareAxes(POSITION | ID | SLOT);
@@ -7639,8 +7737,8 @@
         configureDevice(InputReaderConfiguration::CHANGE_DISPLAY_INFO);
     }
 
-    void processPositionAndVerify(MultiTouchInputMapper& mapper, int32_t xInside, int32_t yInside,
-                                  int32_t xOutside, int32_t yOutside, int32_t xExpected,
+    void processPositionAndVerify(MultiTouchInputMapper& mapper, int32_t xOutside, int32_t yOutside,
+                                  int32_t xInside, int32_t yInside, int32_t xExpected,
                                   int32_t yExpected) {
         // touch on outside area should not work.
         processPosition(mapper, toRawX(xOutside), toRawY(yOutside));
diff --git a/services/inputflinger/tests/TestInputListener.cpp b/services/inputflinger/tests/TestInputListener.cpp
index 352995c..1050ab8 100644
--- a/services/inputflinger/tests/TestInputListener.cpp
+++ b/services/inputflinger/tests/TestInputListener.cpp
@@ -14,11 +14,10 @@
  * limitations under the License.
  */
 
+#include "TestInputListener.h"
 
 #include <gtest/gtest.h>
 
-#include "TestInputListener.h"
-
 namespace android {
 
 // --- TestInputListener ---
@@ -28,7 +27,7 @@
       : mEventHappenedTimeout(eventHappenedTimeout),
         mEventDidNotHappenTimeout(eventDidNotHappenTimeout) {}
 
-TestInputListener::~TestInputListener() { }
+TestInputListener::~TestInputListener() {}
 
 void TestInputListener::assertNotifyConfigurationChangedWasCalled(
         NotifyConfigurationChangedArgs* outEventArgs) {
@@ -43,8 +42,7 @@
             "notifyConfigurationChanged() should not be called."));
 }
 
-void TestInputListener::assertNotifyDeviceResetWasCalled(
-        NotifyDeviceResetArgs* outEventArgs) {
+void TestInputListener::assertNotifyDeviceResetWasCalled(NotifyDeviceResetArgs* outEventArgs) {
     ASSERT_NO_FATAL_FAILURE(
             assertCalled<
                     NotifyDeviceResetArgs>(outEventArgs,
@@ -73,7 +71,7 @@
 
 void TestInputListener::assertNotifyMotionWasNotCalled() {
     ASSERT_NO_FATAL_FAILURE(
-            assertNotCalled<NotifySwitchArgs>("notifySwitch() should not be called."));
+            assertNotCalled<NotifyMotionArgs>("notifyMotion() should not be called."));
 }
 
 void TestInputListener::assertNotifySwitchWasCalled(NotifySwitchArgs* outEventArgs) {
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index dc99986..325ecfe 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -440,7 +440,7 @@
                                                                      mName, mFrameTimelineVsyncId);
         surfaceFrame->setActualQueueTime(systemTime());
 
-        mQueueItems.push_back({item, std::move(surfaceFrame)});
+        mQueueItems.push_back({item, surfaceFrame});
         mQueuedFrames++;
 
         // Wake up any pending callbacks
diff --git a/services/surfaceflinger/BufferQueueLayer.h b/services/surfaceflinger/BufferQueueLayer.h
index b45900e..5a6b9bc 100644
--- a/services/surfaceflinger/BufferQueueLayer.h
+++ b/services/surfaceflinger/BufferQueueLayer.h
@@ -129,10 +129,10 @@
     Condition mQueueItemCondition;
 
     struct BufferData {
-        BufferData(BufferItem item, std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame)
-              : item(item), surfaceFrame(std::move(surfaceFrame)) {}
+        BufferData(BufferItem item, std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame)
+              : item(item), surfaceFrame(surfaceFrame) {}
         BufferItem item;
-        std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame;
+        std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame;
     };
     std::vector<BufferData> mQueueItems;
     std::atomic<uint64_t> mLastFrameNumberReceived{0};
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 963e541..b6c59cd 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -65,10 +65,70 @@
     }
 }
 
+status_t BufferStateLayer::addReleaseFence(const sp<CallbackHandle>& ch,
+                                           const sp<Fence>& fence) {
+    if (ch == nullptr) {
+        return OK;
+    }
+    if (!ch->previousReleaseFence.get()) {
+        ch->previousReleaseFence = fence;
+        return OK;
+    }
+
+    // Below logic is lifted from ConsumerBase.cpp:
+    // Check status of fences first because merging is expensive.
+    // Merging an invalid fence with any other fence results in an
+    // invalid fence.
+    auto currentStatus = ch->previousReleaseFence->getStatus();
+    if (currentStatus == Fence::Status::Invalid) {
+        ALOGE("Existing fence has invalid state, layer: %s", mName.c_str());
+        return BAD_VALUE;
+    }
+
+    auto incomingStatus = fence->getStatus();
+    if (incomingStatus == Fence::Status::Invalid) {
+        ALOGE("New fence has invalid state, layer: %s", mName.c_str());
+        ch->previousReleaseFence = fence;
+        return BAD_VALUE;
+    }
+
+    // If both fences are signaled or both are unsignaled, we need to merge
+    // them to get an accurate timestamp.
+    if (currentStatus == incomingStatus) {
+        char fenceName[32] = {};
+        snprintf(fenceName, 32, "%.28s", mName.c_str());
+        sp<Fence> mergedFence = Fence::merge(
+                fenceName, ch->previousReleaseFence, fence);
+        if (!mergedFence.get()) {
+            ALOGE("failed to merge release fences, layer: %s", mName.c_str());
+            // synchronization is broken, the best we can do is hope fences
+            // signal in order so the new fence will act like a union
+            ch->previousReleaseFence = fence;
+            return BAD_VALUE;
+        }
+        ch->previousReleaseFence = mergedFence;
+    } else if (incomingStatus == Fence::Status::Unsignaled) {
+        // If one fence has signaled and the other hasn't, the unsignaled
+        // fence will approximately correspond with the correct timestamp.
+        // There's a small race if both fences signal at about the same time
+        // and their statuses are retrieved with unfortunate timing. However,
+        // by this point, they will have both signaled and only the timestamp
+        // will be slightly off; any dependencies after this point will
+        // already have been met.
+        ch->previousReleaseFence = fence;
+    }
+    // else if (currentStatus == Fence::Status::Unsignaled) is a no-op.
+
+    return OK;
+}
+
 // -----------------------------------------------------------------------
 // Interface implementation for Layer
 // -----------------------------------------------------------------------
 void BufferStateLayer::onLayerDisplayed(const sp<Fence>& releaseFence) {
+    if (!releaseFence->isValid()) {
+        return;
+    }
     // The previous release fence notifies the client that SurfaceFlinger is done with the previous
     // buffer that was presented on this layer. The first transaction that came in this frame that
     // replaced the previous buffer on this layer needs this release fence, because the fence will
@@ -85,12 +145,17 @@
     // buffer. It replaces the buffer in the second transaction. The buffer in the second
     // transaction will now no longer be presented so it is released immediately and the third
     // transaction doesn't need a previous release fence.
+    sp<CallbackHandle> ch;
     for (auto& handle : mDrawingState.callbackHandles) {
         if (handle->releasePreviousBuffer) {
-            handle->previousReleaseFence = releaseFence;
+            ch = handle;
             break;
         }
     }
+    auto status = addReleaseFence(ch, releaseFence);
+    if (status != OK) {
+        ALOGE("Failed to add release fence for layer %s", getName().c_str());
+    }
 
     mPreviousReleaseFence = releaseFence;
 
@@ -100,14 +165,30 @@
     }
 }
 
+void BufferStateLayer::onSurfaceFrameCreated(
+        const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame) {
+    mPendingJankClassifications.emplace_back(surfaceFrame);
+}
+
 void BufferStateLayer::releasePendingBuffer(nsecs_t dequeueReadyTime) {
     for (const auto& handle : mDrawingState.callbackHandles) {
         handle->transformHint = mTransformHint;
         handle->dequeueReadyTime = dequeueReadyTime;
     }
 
+    std::vector<JankData> jankData;
+    jankData.reserve(mPendingJankClassifications.size());
+    while (!mPendingJankClassifications.empty()
+            && mPendingJankClassifications.front()->getJankType()) {
+        std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame =
+                mPendingJankClassifications.front();
+        mPendingJankClassifications.pop_front();
+        jankData.emplace_back(
+                JankData(surfaceFrame->getToken(), surfaceFrame->getJankType().value()));
+    }
+
     mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
-            mDrawingState.callbackHandles);
+            mDrawingState.callbackHandles, jankData);
 
     mDrawingState.callbackHandles = {};
 
@@ -382,7 +463,7 @@
 
 void BufferStateLayer::forceSendCallbacks() {
     mFlinger->getTransactionCompletedThread().finalizePendingCallbackHandles(
-            mCurrentState.callbackHandles);
+            mCurrentState.callbackHandles, std::vector<JankData>());
 }
 
 bool BufferStateLayer::setTransparentRegionHint(const Region& transparent) {
@@ -398,6 +479,10 @@
         return Rect(getActiveWidth(s), getActiveHeight(s));
     }
 
+    if (mBufferInfo.mBuffer == nullptr) {
+        return Rect::INVALID_RECT;
+    }
+
     // if the display frame is not defined, use the parent bounds as the buffer size.
     const auto& p = mDrawingParent.promote();
     if (p != nullptr) {
diff --git a/services/surfaceflinger/BufferStateLayer.h b/services/surfaceflinger/BufferStateLayer.h
index 42be62a..69b27e4 100644
--- a/services/surfaceflinger/BufferStateLayer.h
+++ b/services/surfaceflinger/BufferStateLayer.h
@@ -115,6 +115,7 @@
 protected:
     void gatherBufferInfo() override;
     uint64_t getHeadFrameNumber(nsecs_t expectedPresentTime) const;
+    void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>& surfaceFrame);
 
 private:
     friend class SlotGenerationTest;
@@ -122,6 +123,8 @@
     bool updateFrameEventHistory(const sp<Fence>& acquireFence, nsecs_t postedTime,
                                  nsecs_t requestedPresentTime);
 
+    status_t addReleaseFence(const sp<CallbackHandle>& ch, const sp<Fence>& releaseFence);
+
     uint64_t getFrameNumber(nsecs_t expectedPresentTime) const override;
 
     bool latchSidebandStream(bool& recomputeVisibleRegions) override;
@@ -158,6 +161,8 @@
     bool mReleasePreviousBuffer = false;
     nsecs_t mCallbackHandleAcquireTime = -1;
 
+    std::deque<std::shared_ptr<android::frametimeline::SurfaceFrame>> mPendingJankClassifications;
+
     // TODO(marissaw): support sticky transform for LEGACY camera mode
 
     class HwcSlotGenerator : public ClientCache::ErasedRecipient {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 247ee23..2ac67cb 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -72,6 +72,7 @@
         mOutputUsage(GRALLOC_USAGE_HW_COMPOSER),
         mProducerSlotSource(0),
         mProducerBuffers(),
+        mProducerSlotNeedReallocation(0),
         mQueueBufferOutput(),
         mSinkBufferWidth(0),
         mSinkBufferHeight(0),
@@ -337,10 +338,14 @@
             dbgSourceStr(source), *sslot, pslot, result);
     uint64_t sourceBit = static_cast<uint64_t>(source) << pslot;
 
+    // reset producer slot reallocation flag
+    mProducerSlotNeedReallocation &= ~(1ULL << pslot);
+
     if ((mProducerSlotSource & (1ULL << pslot)) != sourceBit) {
         // This slot was previously dequeued from the other source; must
         // re-request the buffer.
-        result |= BUFFER_NEEDS_REALLOCATION;
+        mProducerSlotNeedReallocation |= 1ULL << pslot;
+
         mProducerSlotSource &= ~(1ULL << pslot);
         mProducerSlotSource |= sourceBit;
     }
@@ -362,6 +367,9 @@
                 dbgSourceStr(source), pslot, mProducerBuffers[pslot].get(),
                 mProducerBuffers[pslot]->getPixelFormat(),
                 mProducerBuffers[pslot]->getUsage());
+
+        // propagate reallocation to VDS consumer
+        mProducerSlotNeedReallocation |= 1ULL << pslot;
     }
 
     return result;
@@ -436,6 +444,11 @@
     if (outBufferAge) {
         *outBufferAge = 0;
     }
+
+    if ((mProducerSlotNeedReallocation & (1ULL << *pslot)) != 0) {
+        result |= BUFFER_NEEDS_REALLOCATION;
+    }
+
     return result;
 }
 
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 1974625..fba0e3b 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -176,6 +176,10 @@
     uint64_t mProducerSlotSource;
     sp<GraphicBuffer> mProducerBuffers[BufferQueueDefs::NUM_BUFFER_SLOTS];
 
+    // Need to propagate reallocation to VDS consumer.
+    // Each bit corresponds to a producer slot.
+    uint64_t mProducerSlotNeedReallocation;
+
     // The QueueBufferOutput with the latest info from the sink, and with the
     // transform hint cleared. Since we defer queueBuffer from the GPU driver
     // to the sink, we have to return the previous version.
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
index b45c213..b09f07a 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.cpp
@@ -265,8 +265,11 @@
     mJankMetadata = jankMetadata;
 }
 
-JankType SurfaceFrame::getJankType() const {
+std::optional<JankType> SurfaceFrame::getJankType() const {
     std::lock_guard<std::mutex> lock(mMutex);
+    if (mActuals.presentTime == 0) {
+        return std::nullopt;
+    }
     return mJankType;
 }
 
@@ -386,37 +389,36 @@
     this->surfaceFrames.reserve(kNumSurfaceFramesInitial);
 }
 
-std::unique_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
+std::shared_ptr<android::frametimeline::SurfaceFrame> FrameTimeline::createSurfaceFrameForToken(
         pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName,
         std::optional<int64_t> token) {
     ATRACE_CALL();
     if (!token) {
-        return std::make_unique<impl::SurfaceFrame>(ISurfaceComposer::INVALID_VSYNC_ID, ownerPid,
+        return std::make_shared<impl::SurfaceFrame>(ISurfaceComposer::INVALID_VSYNC_ID,ownerPid,
                                                     ownerUid, std::move(layerName),
                                                     std::move(debugName), PredictionState::None,
                                                     TimelineItem());
     }
     std::optional<TimelineItem> predictions = mTokenManager.getPredictionsForToken(*token);
     if (predictions) {
-        return std::make_unique<impl::SurfaceFrame>(*token, ownerPid, ownerUid,
+        return std::make_shared<impl::SurfaceFrame>(*token, ownerPid, ownerUid,
                                                     std::move(layerName), std::move(debugName),
                                                     PredictionState::Valid,
                                                     std::move(*predictions));
     }
-    return std::make_unique<impl::SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName),
+    return std::make_shared<impl::SurfaceFrame>(*token, ownerPid, ownerUid, std::move(layerName),
                                                 std::move(debugName), PredictionState::Expired,
                                                 TimelineItem());
 }
 
 void FrameTimeline::addSurfaceFrame(
-        std::unique_ptr<android::frametimeline::SurfaceFrame> surfaceFrame,
+        std::shared_ptr<android::frametimeline::SurfaceFrame> surfaceFrame,
         SurfaceFrame::PresentState state) {
     ATRACE_CALL();
     surfaceFrame->setPresentState(state);
-    std::unique_ptr<impl::SurfaceFrame> implSurfaceFrame(
-            static_cast<impl::SurfaceFrame*>(surfaceFrame.release()));
     std::lock_guard<std::mutex> lock(mMutex);
-    mCurrentDisplayFrame->surfaceFrames.push_back(std::move(implSurfaceFrame));
+    mCurrentDisplayFrame->surfaceFrames.push_back(
+            std::static_pointer_cast<impl::SurfaceFrame>(surfaceFrame));
 }
 
 void FrameTimeline::setSfWakeUp(int64_t token, nsecs_t wakeUpTime) {
diff --git a/services/surfaceflinger/FrameTimeline/FrameTimeline.h b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
index fe83ebf..084935b 100644
--- a/services/surfaceflinger/FrameTimeline/FrameTimeline.h
+++ b/services/surfaceflinger/FrameTimeline/FrameTimeline.h
@@ -120,6 +120,12 @@
     virtual void setActualStartTime(nsecs_t actualStartTime) = 0;
     virtual void setActualQueueTime(nsecs_t actualQueueTime) = 0;
     virtual void setAcquireFenceTime(nsecs_t acquireFenceTime) = 0;
+
+    // Retrieves jank classification, if it's already been classified.
+    virtual std::optional<JankType> getJankType() const = 0;
+
+    // Token identifying the frame.
+    virtual int64_t getToken() const = 0;
 };
 
 /*
@@ -138,13 +144,13 @@
     // Create a new surface frame, set the predictions based on a token and return it to the caller.
     // Sets the PredictionState of SurfaceFrame.
     // Debug name is the human-readable debugging string for dumpsys.
-    virtual std::unique_ptr<SurfaceFrame> createSurfaceFrameForToken(
+    virtual std::shared_ptr<SurfaceFrame> createSurfaceFrameForToken(
             pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName,
             std::optional<int64_t> token) = 0;
 
     // Adds a new SurfaceFrame to the current DisplayFrame. Frames from multiple layers can be
     // composited into one display frame.
-    virtual void addSurfaceFrame(std::unique_ptr<SurfaceFrame> surfaceFrame,
+    virtual void addSurfaceFrame(std::shared_ptr<SurfaceFrame> surfaceFrame,
                                  SurfaceFrame::PresentState state) = 0;
 
     // The first function called by SF for the current DisplayFrame. Fetches SF predictions based on
@@ -209,8 +215,8 @@
     PresentState getPresentState() const override;
     PredictionState getPredictionState() const override { return mPredictionState; };
     pid_t getOwnerPid() const override { return mOwnerPid; };
-    JankType getJankType() const;
-    int64_t getToken() const { return mToken; };
+    std::optional<JankType> getJankType() const override;
+    int64_t getToken() const override { return mToken; };
     nsecs_t getBaseTime() const;
     uid_t getOwnerUid() const { return mOwnerUid; };
     const std::string& getName() const { return mLayerName; };
@@ -258,10 +264,10 @@
     ~FrameTimeline() = default;
 
     frametimeline::TokenManager* getTokenManager() override { return &mTokenManager; }
-    std::unique_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForToken(
+    std::shared_ptr<frametimeline::SurfaceFrame> createSurfaceFrameForToken(
             pid_t ownerPid, uid_t ownerUid, std::string layerName, std::string debugName,
             std::optional<int64_t> token) override;
-    void addSurfaceFrame(std::unique_ptr<frametimeline::SurfaceFrame> surfaceFrame,
+    void addSurfaceFrame(std::shared_ptr<frametimeline::SurfaceFrame> surfaceFrame,
                          SurfaceFrame::PresentState state) override;
     void setSfWakeUp(int64_t token, nsecs_t wakeupTime) override;
     void setSfPresent(nsecs_t sfPresentTime,
@@ -299,7 +305,7 @@
         TimelineItem surfaceFlingerActuals;
 
         // Collection of predictions and actual values sent over by Layers
-        std::vector<std::unique_ptr<SurfaceFrame>> surfaceFrames;
+        std::vector<std::shared_ptr<SurfaceFrame>> surfaceFrames;
 
         PredictionState predictionState = PredictionState::None;
         JankType jankType = JankType::None; // Enum for the type of jank
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 7e7f9fc..d5b599a 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -819,7 +819,8 @@
             // to be applied as per normal (no synchronization).
             mCurrentState.barrierLayer_legacy = nullptr;
         } else {
-            auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.barrierFrameNumber, this);
+            auto syncPoint = std::make_shared<SyncPoint>(mCurrentState.barrierFrameNumber, this,
+                                                         barrierLayer);
             if (barrierLayer->addSyncPoint(syncPoint)) {
                 std::stringstream ss;
                 ss << "Adding sync point " << mCurrentState.barrierFrameNumber;
@@ -844,7 +845,7 @@
     ATRACE_CALL();
 
     *stateToCommit = mPendingStates[0];
-    mPendingStates.removeAt(0);
+    mPendingStates.pop_front();
     ATRACE_INT(mTransactionName.c_str(), mPendingStates.size());
 }
 
@@ -883,6 +884,7 @@
                 mRemoteSyncPoints.pop_front();
             } else {
                 ATRACE_NAME("!frameIsAvailable");
+                mRemoteSyncPoints.front()->checkTimeoutAndLog();
                 break;
             }
         } else {
@@ -906,17 +908,17 @@
                 ? std::nullopt
                 : std::make_optional(stateToCommit->frameTimelineVsyncId);
 
-        auto surfaceFrame =
+        mSurfaceFrame =
                 mFlinger->mFrameTimeline->createSurfaceFrameForToken(getOwnerPid(), getOwnerUid(),
                                                                      mName, mTransactionName,
                                                                      vsyncId);
-        surfaceFrame->setActualQueueTime(stateToCommit->postTime);
+        mSurfaceFrame->setActualQueueTime(stateToCommit->postTime);
         // For transactions we set the acquire fence time to the post time as we
         // don't have a buffer. For BufferStateLayer it is overridden in
         // BufferStateLayer::applyPendingStates
-        surfaceFrame->setAcquireFenceTime(stateToCommit->postTime);
+        mSurfaceFrame->setAcquireFenceTime(stateToCommit->postTime);
 
-        mSurfaceFrame = std::move(surfaceFrame);
+        onSurfaceFrameCreated(mSurfaceFrame);
     }
 
     mCurrentState.modified = false;
@@ -1062,7 +1064,7 @@
 
 void Layer::commitTransaction(const State& stateToCommit) {
     mDrawingState = stateToCommit;
-    mFlinger->mFrameTimeline->addSurfaceFrame(std::move(mSurfaceFrame), PresentState::Presented);
+    mFlinger->mFrameTimeline->addSurfaceFrame(mSurfaceFrame, PresentState::Presented);
 }
 
 uint32_t Layer::getTransactionFlags(uint32_t flags) {
@@ -1279,7 +1281,8 @@
     t.set(matrix.dsdx, matrix.dtdy, matrix.dtdx, matrix.dsdy);
 
     if (!allowNonRectPreservingTransforms && !t.preserveRects()) {
-        ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER ignored");
+        ALOGW("Attempt to set rotation matrix without permission ACCESS_SURFACE_FLINGER nor "
+              "ROTATE_SURFACE_FLINGER ignored");
         return false;
     }
     mCurrentState.sequence++;
@@ -2431,27 +2434,7 @@
     return mRemovedFromCurrentState;
 }
 
-InputWindowInfo Layer::fillInputInfo() {
-    if (!hasInputInfo()) {
-        mDrawingState.inputInfo.name = getName();
-        mDrawingState.inputInfo.ownerUid = mCallingUid;
-        mDrawingState.inputInfo.ownerPid = mCallingPid;
-        mDrawingState.inputInfo.inputFeatures = InputWindowInfo::Feature::NO_INPUT_CHANNEL;
-        mDrawingState.inputInfo.flags = InputWindowInfo::Flag::NOT_TOUCH_MODAL;
-        mDrawingState.inputInfo.displayId = getLayerStack();
-    }
-
-    InputWindowInfo info = mDrawingState.inputInfo;
-    info.id = sequence;
-
-    if (info.displayId == ADISPLAY_ID_NONE) {
-        info.displayId = getLayerStack();
-    }
-
-    ui::Transform t = getTransform();
-    int32_t xSurfaceInset = info.surfaceInset;
-    int32_t ySurfaceInset = info.surfaceInset;
-
+void Layer::fillInputFrameInfo(InputWindowInfo& info) {
     // Transform layer size to screen space and inset it by surface insets.
     // If this is a portal window, set the touchableRegion to the layerBounds.
     Rect layerBounds = info.portalToDisplayId == ADISPLAY_ID_NONE
@@ -2461,6 +2444,20 @@
         layerBounds = getCroppedBufferSize(getDrawingState());
     }
 
+    if (!layerBounds.isValid()) {
+        // If the layer bounds is empty, set the frame to empty and clear the transform
+        info.frameLeft = 0;
+        info.frameTop = 0;
+        info.frameRight = 0;
+        info.frameBottom = 0;
+        info.transform.reset();
+        return;
+    }
+
+    ui::Transform t = getTransform();
+    int32_t xSurfaceInset = info.surfaceInset;
+    int32_t ySurfaceInset = info.surfaceInset;
+
     const float xScale = t.getScaleX();
     const float yScale = t.getScaleY();
     if (xScale != 1.0f || yScale != 1.0f) {
@@ -2527,6 +2524,27 @@
     // Position the touchable region relative to frame screen location and restrict it to frame
     // bounds.
     info.touchableRegion = inputTransform.transform(info.touchableRegion);
+}
+
+InputWindowInfo Layer::fillInputInfo() {
+    if (!hasInputInfo()) {
+        mDrawingState.inputInfo.name = getName();
+        mDrawingState.inputInfo.ownerUid = mOwnerUid;
+        mDrawingState.inputInfo.ownerPid = mOwnerPid;
+        mDrawingState.inputInfo.inputFeatures = InputWindowInfo::Feature::NO_INPUT_CHANNEL;
+        mDrawingState.inputInfo.flags = InputWindowInfo::Flag::NOT_TOUCH_MODAL;
+        mDrawingState.inputInfo.displayId = getLayerStack();
+    }
+
+    InputWindowInfo info = mDrawingState.inputInfo;
+    info.id = sequence;
+
+    if (info.displayId == ADISPLAY_ID_NONE) {
+        info.displayId = getLayerStack();
+    }
+
+    fillInputFrameInfo(info);
+
     // For compatibility reasons we let layers which can receive input
     // receive input before they have actually submitted a buffer. Because
     // of this we use canReceiveInput instead of isVisible to check the
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index e9fd550..2cfdba3 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -36,6 +36,7 @@
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
 
+#include <chrono>
 #include <cstdint>
 #include <list>
 #include <optional>
@@ -902,12 +903,13 @@
 protected:
     class SyncPoint {
     public:
-        explicit SyncPoint(uint64_t frameNumber, wp<Layer> requestedSyncLayer)
+        explicit SyncPoint(uint64_t frameNumber, wp<Layer> requestedSyncLayer,
+                           wp<Layer> barrierLayer_legacy)
               : mFrameNumber(frameNumber),
                 mFrameIsAvailable(false),
                 mTransactionIsApplied(false),
-                mRequestedSyncLayer(requestedSyncLayer) {}
-
+                mRequestedSyncLayer(requestedSyncLayer),
+                mBarrierLayer_legacy(barrierLayer_legacy) {}
         uint64_t getFrameNumber() const { return mFrameNumber; }
 
         bool frameIsAvailable() const { return mFrameIsAvailable; }
@@ -920,11 +922,42 @@
 
         sp<Layer> getRequestedSyncLayer() { return mRequestedSyncLayer.promote(); }
 
+        sp<Layer> getBarrierLayer() const { return mBarrierLayer_legacy.promote(); }
+
+        bool isTimeout() const {
+            using namespace std::chrono_literals;
+            static constexpr std::chrono::nanoseconds TIMEOUT_THRESHOLD = 1s;
+
+            return std::chrono::steady_clock::now() - mCreateTimeStamp > TIMEOUT_THRESHOLD;
+        }
+
+        void checkTimeoutAndLog() {
+            using namespace std::chrono_literals;
+            static constexpr std::chrono::nanoseconds LOG_PERIOD = 1s;
+
+            if (!frameIsAvailable() && isTimeout()) {
+                const auto now = std::chrono::steady_clock::now();
+                if (now - mLastLogTime > LOG_PERIOD) {
+                    mLastLogTime = now;
+                    sp<Layer> requestedSyncLayer = getRequestedSyncLayer();
+                    sp<Layer> barrierLayer = getBarrierLayer();
+                    ALOGW("[%s] sync point %" PRIu64 " wait timeout %lld for %s",
+                          requestedSyncLayer ? requestedSyncLayer->getDebugName() : "Removed",
+                          mFrameNumber, (now - mCreateTimeStamp).count(),
+                          barrierLayer ? barrierLayer->getDebugName() : "Removed");
+                }
+            }
+        }
+
     private:
         const uint64_t mFrameNumber;
         std::atomic<bool> mFrameIsAvailable;
         std::atomic<bool> mTransactionIsApplied;
         wp<Layer> mRequestedSyncLayer;
+        wp<Layer> mBarrierLayer_legacy;
+        const std::chrono::time_point<std::chrono::steady_clock> mCreateTimeStamp =
+                std::chrono::steady_clock::now();
+        std::chrono::time_point<std::chrono::steady_clock> mLastLogTime;
     };
 
     friend class impl::SurfaceInterceptor;
@@ -944,6 +977,7 @@
     virtual void commitTransaction(const State& stateToCommit);
     virtual bool applyPendingStates(State* stateToCommit);
     virtual uint32_t doTransactionResize(uint32_t flags, Layer::State* stateToCommit);
+    virtual void onSurfaceFrameCreated(const std::shared_ptr<frametimeline::SurfaceFrame>&) {}
 
     // Returns mCurrentScaling mode (originating from the
     // Client) or mOverrideScalingMode mode (originating from
@@ -1010,12 +1044,12 @@
     State mDrawingState;
     // Store a copy of the pending state so that the drawing thread can access the
     // states without a lock.
-    Vector<State> mPendingStatesSnapshot;
+    std::deque<State> mPendingStatesSnapshot;
 
     // these are protected by an external lock (mStateLock)
     State mCurrentState;
     std::atomic<uint32_t> mTransactionFlags{0};
-    Vector<State> mPendingStates;
+    std::deque<State> mPendingStates;
 
     // Timestamp history for UIAutomation. Thread safe.
     FrameTracker mFrameTracker;
@@ -1068,7 +1102,7 @@
     const InputWindowInfo::Type mWindowType;
 
     // Can only be accessed with the SF state lock held.
-    std::unique_ptr<frametimeline::SurfaceFrame> mSurfaceFrame;
+    std::shared_ptr<frametimeline::SurfaceFrame> mSurfaceFrame;
 
     // The owner of the layer. If created from a non system process, it will be the calling uid.
     // If created from a system process, the value can be passed in.
@@ -1113,6 +1147,9 @@
     // null.
     sp<Layer> getRootLayer();
 
+    // Fills in the frame and transform info for the InputWindowInfo
+    void fillInputFrameInfo(InputWindowInfo& info);
+
     // Cached properties computed from drawing state
     // Effective transform taking into account parent transforms and any parent scaling, which is
     // a transform from the current layer coordinate space to display(screen) coordinate space.
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 5d6505f..85c98a5 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -274,6 +274,7 @@
 
 const String16 sHardwareTest("android.permission.HARDWARE_TEST");
 const String16 sAccessSurfaceFlinger("android.permission.ACCESS_SURFACE_FLINGER");
+const String16 sRotateSurfaceFlinger("android.permission.ROTATE_SURFACE_FLINGER");
 const String16 sReadFramebuffer("android.permission.READ_FRAME_BUFFER");
 const String16 sDump("android.permission.DUMP");
 const char* KERNEL_IDLE_TIMER_PROP = "graphics.display.kernel_idle_timer.enabled";
@@ -324,6 +325,14 @@
     }
 }
 
+bool callingThreadHasRotateSurfaceFlingerAccess() {
+    IPCThreadState* ipc = IPCThreadState::self();
+    const int pid = ipc->getCallingPid();
+    const int uid = ipc->getCallingUid();
+    return uid == AID_GRAPHICS || uid == AID_SYSTEM ||
+            PermissionCache::checkPermission(sRotateSurfaceFlinger, pid, uid);
+}
+
 SurfaceFlingerBE::SurfaceFlingerBE() : mHwcServiceName(getHwcServiceName()) {}
 
 SurfaceFlinger::SurfaceFlinger(Factory& factory, SkipInitializationTag)
@@ -1987,12 +1996,14 @@
 
     mScheduler->onDisplayRefreshed(presentTime);
 
-    postFrame();
-    postComposition();
-
+    // Set presentation information before calling postComposition, such that jank information from
+    // this' frame classification is already available when sending jank info to clients.
     mFrameTimeline->setSfPresent(systemTime(),
                                  std::make_shared<FenceTime>(mPreviousPresentFences[0]));
 
+    postFrame();
+    postComposition();
+
     const bool prevFrameHadClientComposition = mHadClientComposition;
 
     mHadClientComposition = std::any_of(displays.cbegin(), displays.cend(), [](const auto& pair) {
@@ -2562,7 +2573,8 @@
 }
 
 void SurfaceFlinger::processDisplayRemoved(const wp<IBinder>& displayToken) {
-    if (const auto display = getDisplayDeviceLocked(displayToken)) {
+    auto display = getDisplayDeviceLocked(displayToken);
+    if (display) {
         display->disconnect();
         if (!display->isVirtual()) {
             dispatchDisplayHotplugEvent(display->getPhysicalId(), false);
@@ -2570,6 +2582,22 @@
     }
 
     mDisplays.erase(displayToken);
+
+    if (display && display->isVirtual()) {
+        static_cast<void>(schedule([display = std::move(display)] {
+            // Destroy the display without holding the mStateLock.
+            // This is a temporary solution until we can manage transaction queues without
+            // holding the mStateLock.
+            // With blast, the IGBP that is passed to the VirtualDisplaySurface is owned by the
+            // client. When the IGBP is disconnected, its buffer cache in SF will be cleared
+            // via SurfaceComposerClient::doUncacheBufferTransaction. This call from the client
+            // ends up running on the main thread causing a deadlock since setTransactionstate
+            // will try to acquire the mStateLock. Instead we extend the lifetime of
+            // DisplayDevice and destroy it in the main thread without holding the mStateLock.
+            // The display will be disconnected and removed from the mDisplays list so it will
+            // not be accessible.
+        }));
+    }
 }
 
 void SurfaceFlinger::processDisplayChanged(const wp<IBinder>& displayToken,
@@ -3659,15 +3687,20 @@
         // must now be cropped to a non rectangular 8 sided region.
         //
         // Of course we can fix this in the future. For now, we are lucky, SurfaceControl is
-        // private API, and the WindowManager only uses rotation in one case, which is on a top
-        // level layer in which cropping is not an issue.
+        // private API, and arbitrary rotation is used in limited use cases, for instance:
+        // - WindowManager only uses rotation in one case, which is on a top level layer in which
+        //   cropping is not an issue.
+        // - Launcher, as a privileged app, uses this to transition an application to PiP
+        //   (picture-in-picture) mode.
         //
         // However given that abuse of rotation matrices could lead to surfaces extending outside
-        // of cropped areas, we need to prevent non-root clients without permission ACCESS_SURFACE_FLINGER
-        // (a.k.a. everyone except WindowManager and tests) from setting non rectangle preserving
-        // transformations.
-        if (layer->setMatrix(s.matrix, privileged))
-            flags |= eTraversalNeeded;
+        // of cropped areas, we need to prevent non-root clients without permission
+        // ACCESS_SURFACE_FLINGER nor ROTATE_SURFACE_FLINGER
+        // (a.k.a. everyone except WindowManager / tests / Launcher) from setting non rectangle
+        // preserving transformations.
+        bool allowNonRectPreservingTransforms =
+                privileged || callingThreadHasRotateSurfaceFlingerAccess();
+        if (layer->setMatrix(s.matrix, allowNonRectPreservingTransforms)) flags |= eTraversalNeeded;
     }
     if (what & layer_state_t::eTransparentRegionChanged) {
         if (layer->setTransparentRegionHint(s.transparentRegion))
@@ -4882,10 +4915,11 @@
         case CAPTURE_LAYERS:
         case CAPTURE_DISPLAY:
         case SET_DISPLAY_BRIGHTNESS:
-        case SET_FRAME_TIMELINE_VSYNC: {
+        case SET_FRAME_TIMELINE_VSYNC:
+        // This is not sensitive information, so should not require permission control.
+        case GET_GPU_CONTEXT_PRIORITY: {
             return OK;
         }
-
         case ADD_REGION_SAMPLING_LISTENER:
         case REMOVE_REGION_SAMPLING_LISTENER: {
             // codes that require permission check
@@ -6307,6 +6341,13 @@
     return NO_ERROR;
 }
 
+int SurfaceFlinger::getGPUContextPriority() {
+    // TODO(b/168740533): This is a proof of concept. Once REAL time priority is available
+    // in EGL, we can return it in RenderEngine and propagate it to SurfaceFlinger. Until
+    // then return IntentFilter.SYSTEM_HIGH_PRIORITY.
+    return 1000;
+}
+
 } // namespace android
 
 #if defined(__gl_h_)
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 0509247..2e4d1ce 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -608,6 +608,8 @@
     status_t addTransactionTraceListener(
             const sp<gui::ITransactionTraceListener>& listener) override;
 
+    int getGPUContextPriority() override;
+
     // Implements IBinder::DeathRecipient.
     void binderDied(const wp<IBinder>& who) override;
 
diff --git a/services/surfaceflinger/SurfaceTracing.h b/services/surfaceflinger/SurfaceTracing.h
index 576bba7..497ebd3 100644
--- a/services/surfaceflinger/SurfaceTracing.h
+++ b/services/surfaceflinger/SurfaceTracing.h
@@ -85,7 +85,7 @@
     std::unique_ptr<Runner> runner;
 
     struct Config {
-        uint32_t flags = TRACE_CRITICAL | TRACE_INPUT;
+        uint32_t flags = TRACE_CRITICAL | TRACE_INPUT | TRACE_SYNC;
         size_t bufferSize = DEFAULT_BUFFER_SIZE;
     } mConfig;
 
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
index fae4e94..9481cac 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/Android.bp
@@ -42,3 +42,16 @@
         type: "full",
     },
 }
+
+// ====  java device library for timestats proto  ===========================
+// Note timestats is deprecated and is only used for legacy tests
+java_library {
+    name: "timestats-proto",
+    srcs: [
+        "timestats.proto",
+    ],
+    proto: {
+        type: "lite",
+    },
+    sdk_version: "current",
+}
diff --git a/services/surfaceflinger/TransactionCompletedThread.cpp b/services/surfaceflinger/TransactionCompletedThread.cpp
index ca24493..1797af4 100644
--- a/services/surfaceflinger/TransactionCompletedThread.cpp
+++ b/services/surfaceflinger/TransactionCompletedThread.cpp
@@ -153,7 +153,7 @@
 }
 
 status_t TransactionCompletedThread::finalizePendingCallbackHandles(
-        const std::deque<sp<CallbackHandle>>& handles) {
+        const std::deque<sp<CallbackHandle>>& handles, const std::vector<JankData>& jankData) {
     if (handles.empty()) {
         return NO_ERROR;
     }
@@ -186,7 +186,7 @@
             ALOGW("cannot find listener in mPendingTransactions");
         }
 
-        status_t err = addCallbackHandle(handle);
+        status_t err = addCallbackHandle(handle, jankData);
         if (err != NO_ERROR) {
             ALOGE("could not add callback handle");
             return err;
@@ -204,7 +204,7 @@
         return BAD_VALUE;
     }
 
-    return addCallbackHandle(handle);
+    return addCallbackHandle(handle, std::vector<JankData>());
 }
 
 status_t TransactionCompletedThread::findTransactionStats(
@@ -225,7 +225,8 @@
     return BAD_VALUE;
 }
 
-status_t TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle) {
+status_t TransactionCompletedThread::addCallbackHandle(const sp<CallbackHandle>& handle,
+        const std::vector<JankData>& jankData) {
     // If we can't find the transaction stats something has gone wrong. The client should call
     // startRegistration before trying to add a callback handle.
     TransactionStats* transactionStats;
@@ -246,7 +247,7 @@
                                           handle->dequeueReadyTime);
         transactionStats->surfaceStats.emplace_back(surfaceControl, handle->acquireTime,
                                                     handle->previousReleaseFence,
-                                                    handle->transformHint, eventStats);
+                                                    handle->transformHint, eventStats, jankData);
     }
     return NO_ERROR;
 }
diff --git a/services/surfaceflinger/TransactionCompletedThread.h b/services/surfaceflinger/TransactionCompletedThread.h
index f50147a..c4ba7e4 100644
--- a/services/surfaceflinger/TransactionCompletedThread.h
+++ b/services/surfaceflinger/TransactionCompletedThread.h
@@ -73,7 +73,8 @@
     // presented.
     status_t registerPendingCallbackHandle(const sp<CallbackHandle>& handle);
     // Notifies the TransactionCompletedThread that a pending CallbackHandle has been presented.
-    status_t finalizePendingCallbackHandles(const std::deque<sp<CallbackHandle>>& handles);
+    status_t finalizePendingCallbackHandles(const std::deque<sp<CallbackHandle>>& handles,
+                                            const std::vector<JankData>& jankData);
 
     // Adds the Transaction CallbackHandle from a layer that does not need to be relatched and
     // presented this frame.
@@ -93,7 +94,8 @@
                                   const std::vector<CallbackId>& callbackIds,
                                   TransactionStats** outTransactionStats) REQUIRES(mMutex);
 
-    status_t addCallbackHandle(const sp<CallbackHandle>& handle) REQUIRES(mMutex);
+    status_t addCallbackHandle(const sp<CallbackHandle>& handle,
+                               const std::vector<JankData>& jankData) REQUIRES(mMutex);
 
     class ThreadDeathRecipient : public IBinder::DeathRecipient {
     public:
diff --git a/services/surfaceflinger/tests/VirtualDisplay_test.cpp b/services/surfaceflinger/tests/VirtualDisplay_test.cpp
index 9fd2227..18e0806 100644
--- a/services/surfaceflinger/tests/VirtualDisplay_test.cpp
+++ b/services/surfaceflinger/tests/VirtualDisplay_test.cpp
@@ -52,6 +52,8 @@
     virtualDisplay.clear();
     // Sync here to ensure the display was completely destroyed in SF
     t.apply(true);
+    // add another sync since we are deferring the display destruction
+    t.apply(true);
 
     sp<Surface> surface = new Surface(mProducer);
     sp<ANativeWindow> window(surface);
diff --git a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
index 31a5126..538b10d 100644
--- a/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
+++ b/services/surfaceflinger/tests/fakehwc/SFFakeHwc_test.cpp
@@ -69,6 +69,7 @@
 
 using Transaction = SurfaceComposerClient::Transaction;
 using Attribute = V2_4::IComposerClient::Attribute;
+using Display = V2_1::Display;
 
 ///////////////////////////////////////////////
 
diff --git a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
index 411e780..43b5afe 100644
--- a/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
+++ b/services/surfaceflinger/tests/unittests/FrameTimelineTest.cpp
@@ -205,7 +205,7 @@
 
     // Set up the display frame
     mFrameTimeline->setSfWakeUp(token1, 20);
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1), SurfaceFrame::PresentState::Dropped);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1, SurfaceFrame::PresentState::Dropped);
     mFrameTimeline->setSfPresent(25, presentFence1);
     presentFence1->signalForTest(30);
 
@@ -229,11 +229,11 @@
                                                        sLayerNameOne, surfaceFrameToken1);
     auto surfaceFrame2 =
             mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameTwo,
-                                                       sLayerNameTwo, surfaceFrameToken1);
+                                                       sLayerNameTwo, surfaceFrameToken2);
     mFrameTimeline->setSfWakeUp(sfToken1, 22);
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1,
                                     SurfaceFrame::PresentState::Presented);
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame2),
+    mFrameTimeline->addSurfaceFrame(surfaceFrame2,
                                     SurfaceFrame::PresentState::Presented);
     mFrameTimeline->setSfPresent(26, presentFence1);
     auto displayFrame = getDisplayFrame(0);
@@ -246,13 +246,16 @@
     EXPECT_EQ(presentedSurfaceFrame1.getActuals().presentTime, 0);
     EXPECT_EQ(presentedSurfaceFrame2.getActuals().presentTime, 0);
 
+    EXPECT_EQ(surfaceFrame1->getToken(), surfaceFrameToken1);
+    EXPECT_EQ(surfaceFrame2->getToken(), surfaceFrameToken2);
+
     // Trigger a flush by finalizing the next DisplayFrame
     auto presentFence2 = fenceFactory.createFenceTimeForTest(Fence::NO_FENCE);
     auto surfaceFrame3 =
             mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
                                                        sLayerNameOne, surfaceFrameToken2);
     mFrameTimeline->setSfWakeUp(sfToken2, 52);
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame3), SurfaceFrame::PresentState::Dropped);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame3, SurfaceFrame::PresentState::Dropped);
     mFrameTimeline->setSfPresent(56, presentFence2);
     displayFrame = getDisplayFrame(0);
 
@@ -260,6 +263,8 @@
     EXPECT_EQ(displayFrame->surfaceFlingerActuals.presentTime, 42);
     EXPECT_EQ(presentedSurfaceFrame1.getActuals().presentTime, 42);
     EXPECT_EQ(presentedSurfaceFrame2.getActuals().presentTime, 42);
+    EXPECT_NE(surfaceFrame1->getJankType(), std::nullopt);
+    EXPECT_NE(surfaceFrame2->getJankType(), std::nullopt);
 }
 
 TEST_F(FrameTimelineTest, displayFramesSlidingWindowMovesAfterLimit) {
@@ -275,7 +280,7 @@
                 mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
                                                            sLayerNameOne, surfaceFrameToken);
         mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor);
-        mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+        mFrameTimeline->addSurfaceFrame(surfaceFrame,
                                         SurfaceFrame::PresentState::Presented);
         mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
         presentFence->signalForTest(32 + frameTimeFactor);
@@ -297,7 +302,7 @@
             mFrameTimeline->createSurfaceFrameForToken(sPidOne, sUidOne, sLayerNameOne,
                                                        sLayerNameOne, surfaceFrameToken);
     mFrameTimeline->setSfWakeUp(sfToken, 22 + frameTimeFactor);
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame), SurfaceFrame::PresentState::Presented);
+    mFrameTimeline->addSurfaceFrame(surfaceFrame, SurfaceFrame::PresentState::Presented);
     mFrameTimeline->setSfPresent(27 + frameTimeFactor, presentFence);
     presentFence->signalForTest(32 + frameTimeFactor);
     displayFrame0 = getDisplayFrame(0);
@@ -337,7 +342,7 @@
                                                            sLayerNameOne, std::nullopt);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
         mFrameTimeline->setSfWakeUp(sfToken, 22);
-        mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+        mFrameTimeline->addSurfaceFrame(surfaceFrame,
                                         SurfaceFrame::PresentState::Presented);
         mFrameTimeline->setSfPresent(27, presentFence);
     }
@@ -353,7 +358,7 @@
                                                            sLayerNameOne, std::nullopt);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
         mFrameTimeline->setSfWakeUp(sfToken, 22);
-        mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+        mFrameTimeline->addSurfaceFrame(surfaceFrame,
                                         SurfaceFrame::PresentState::Presented);
         mFrameTimeline->setSfPresent(27, presentFence);
     }
@@ -369,7 +374,7 @@
                                                            sLayerNameOne, std::nullopt);
         int64_t sfToken = mTokenManager->generateTokenForPredictions({22, 26, 30});
         mFrameTimeline->setSfWakeUp(sfToken, 22);
-        mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame),
+        mFrameTimeline->addSurfaceFrame(surfaceFrame,
                                         SurfaceFrame::PresentState::Presented);
         mFrameTimeline->setSfPresent(27, presentFence);
     }
@@ -396,10 +401,10 @@
                                                        sLayerNameOne, surfaceFrameToken1);
     mFrameTimeline->setSfWakeUp(sfToken1,
                                 std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count());
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1,
                                     SurfaceFrame::PresentState::Presented);
     presentFence1->signalForTest(
-            std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
+            std::chrono::duration_cast<std::chrono::nanoseconds>(70ms).count());
 
     mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(59ms).count(),
                                  presentFence1);
@@ -423,12 +428,14 @@
                                                        sLayerNameOne, surfaceFrameToken1);
     mFrameTimeline->setSfWakeUp(sfToken1,
                                 std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count());
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1,
                                     SurfaceFrame::PresentState::Presented);
     presentFence1->signalForTest(
             std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
     mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(59ms).count(),
                                  presentFence1);
+    EXPECT_NE(surfaceFrame1->getJankType(), std::nullopt);
+    EXPECT_TRUE((surfaceFrame1->getJankType().value() & JankType::Display) != 0);
 }
 
 TEST_F(FrameTimelineTest, presentFenceSignaled_reportsAppMiss) {
@@ -453,12 +460,15 @@
     mFrameTimeline->setSfWakeUp(sfToken1,
                                 std::chrono::duration_cast<std::chrono::nanoseconds>(52ms).count());
 
-    mFrameTimeline->addSurfaceFrame(std::move(surfaceFrame1),
+    mFrameTimeline->addSurfaceFrame(surfaceFrame1,
                                     SurfaceFrame::PresentState::Presented);
     presentFence1->signalForTest(
             std::chrono::duration_cast<std::chrono::nanoseconds>(90ms).count());
     mFrameTimeline->setSfPresent(std::chrono::duration_cast<std::chrono::nanoseconds>(56ms).count(),
                                  presentFence1);
+
+    EXPECT_NE(surfaceFrame1->getJankType(), std::nullopt);
+    EXPECT_TRUE((surfaceFrame1->getJankType().value() & JankType::AppDeadlineMissed) != 0);
 }
 
 /*
diff --git a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
index 030073c..7f05a75 100644
--- a/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
+++ b/services/surfaceflinger/tests/unittests/TestableSurfaceFlinger.h
@@ -388,6 +388,8 @@
         return mFlinger->onTransact(code, data, reply, flags);
     }
 
+    auto getGPUContextPriority() { return mFlinger->getGPUContextPriority(); }
+
     /* ------------------------------------------------------------------------
      * Read-only access to private data to assert post-conditions.
      */
diff --git a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
index 81c32fe..6b12536 100644
--- a/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
+++ b/services/surfaceflinger/tests/unittests/mock/MockFrameTimeline.h
@@ -31,7 +31,7 @@
 
     MOCK_METHOD0(onBootFinished, void());
     MOCK_METHOD2(addSurfaceFrame,
-                 void(std::unique_ptr<frametimeline::SurfaceFrame>,
+                 void(std::shared_ptr<frametimeline::SurfaceFrame>,
                       frametimeline::SurfaceFrame::PresentState));
     MOCK_METHOD2(setSfWakeUp, void(int64_t, nsecs_t));
     MOCK_METHOD2(setSfPresent, void(nsecs_t, const std::shared_ptr<FenceTime>&));
diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp
index 75228d6..c18bf18 100644
--- a/services/vibratorservice/Android.bp
+++ b/services/vibratorservice/Android.bp
@@ -19,6 +19,7 @@
         "VibratorCallbackScheduler.cpp",
         "VibratorHalController.cpp",
         "VibratorHalWrapper.cpp",
+        "VibratorManagerHalController.cpp",
         "VibratorManagerHalWrapper.cpp",
     ],
 
diff --git a/services/vibratorservice/VibratorManagerHalController.cpp b/services/vibratorservice/VibratorManagerHalController.cpp
index b24e5c4..6bf6581 100644
--- a/services/vibratorservice/VibratorManagerHalController.cpp
+++ b/services/vibratorservice/VibratorManagerHalController.cpp
@@ -26,13 +26,13 @@
 
 namespace vibrator {
 
-std::shared_ptr<ManagerHalWrapper> connectHal(std::shared_ptr<CallbackScheduler> scheduler) {
+std::shared_ptr<ManagerHalWrapper> connectManagerHal(std::shared_ptr<CallbackScheduler> scheduler) {
     static bool gHalExists = true;
     if (gHalExists) {
         sp<Aidl::IVibratorManager> hal = waitForVintfService<Aidl::IVibratorManager>();
         if (hal) {
             ALOGV("Successfully connected to VibratorManager HAL AIDL service.");
-            return std::make_shared<AidlManagerHalWrapper>(std::move(scheduler), aidlHal);
+            return std::make_shared<AidlManagerHalWrapper>(std::move(scheduler), hal);
         }
     }
 
@@ -80,12 +80,11 @@
 
 // -------------------------------------------------------------------------------------------------
 
-bool ManagerHalController::init() {
+void ManagerHalController::init() {
     std::lock_guard<std::mutex> lock(mConnectedHalMutex);
     if (mConnectedHal == nullptr) {
         mConnectedHal = mConnector(mCallbackScheduler);
     }
-    return mConnectedHal != nullptr;
 }
 
 HalResult<void> ManagerHalController::ping() {
diff --git a/services/vibratorservice/include/vibratorservice/VibratorManagerHalController.h b/services/vibratorservice/include/vibratorservice/VibratorManagerHalController.h
index cf82562..9168565 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorManagerHalController.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorManagerHalController.h
@@ -19,6 +19,7 @@
 
 #include <android/hardware/vibrator/IVibratorManager.h>
 #include <vibratorservice/VibratorHalController.h>
+#include <vibratorservice/VibratorManagerHalWrapper.h>
 #include <unordered_map>
 
 namespace android {
@@ -36,7 +37,7 @@
     ManagerHalController()
           : ManagerHalController(std::make_shared<CallbackScheduler>(), &connectManagerHal) {}
     ManagerHalController(std::shared_ptr<CallbackScheduler> callbackScheduler, Connector connector)
-          : mConnector(connector), mConnectedHal(nullptr) {}
+          : mConnector(connector), mCallbackScheduler(callbackScheduler), mConnectedHal(nullptr) {}
     virtual ~ManagerHalController() = default;
 
     /* Connects to the HAL service, possibly waiting for the registered service to
@@ -64,9 +65,10 @@
 
 private:
     Connector mConnector;
+    std::shared_ptr<CallbackScheduler> mCallbackScheduler;
     std::mutex mConnectedHalMutex;
     // Shared pointer to allow local copies to be used by different threads.
-    std::shared_ptr<HalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex);
+    std::shared_ptr<ManagerHalWrapper> mConnectedHal GUARDED_BY(mConnectedHalMutex);
 
     template <typename T>
     HalResult<T> processHalResult(HalResult<T> result, const char* functionName);
diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp
index 6801f76..9af1b7b 100644
--- a/services/vibratorservice/test/Android.bp
+++ b/services/vibratorservice/test/Android.bp
@@ -23,6 +23,7 @@
         "VibratorHalWrapperHidlV1_1Test.cpp",
         "VibratorHalWrapperHidlV1_2Test.cpp",
         "VibratorHalWrapperHidlV1_3Test.cpp",
+        "VibratorManagerHalControllerTest.cpp",
         "VibratorManagerHalWrapperAidlTest.cpp",
         "VibratorManagerHalWrapperLegacyTest.cpp",
     ],
diff --git a/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp b/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp
index 3b036ee..e5fbbae 100644
--- a/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp
+++ b/services/vibratorservice/test/VibratorManagerHalControllerTest.cpp
@@ -22,22 +22,28 @@
 
 #include <utils/Log.h>
 
-#include <vibratorservice/VibratorManagerHalWrapper.h>
+#include <vibratorservice/VibratorManagerHalController.h>
 
 #include "test_utils.h"
 
+using android::vibrator::HalController;
+
 using namespace android;
 using namespace testing;
 
 static constexpr int MAX_ATTEMPTS = 2;
+static const std::vector<int32_t> VIBRATOR_IDS = {1, 2};
+static constexpr int VIBRATOR_ID = 1;
 
 class MockManagerHalWrapper : public vibrator::ManagerHalWrapper {
 public:
+    MOCK_METHOD(void, tryReconnect, (), (override));
     MOCK_METHOD(vibrator::HalResult<void>, ping, (), (override));
-    MOCK_METHOD(vibrator::HalResult<int32_t>, getCapabilities, (), (override));
+    MOCK_METHOD(vibrator::HalResult<vibrator::ManagerCapabilities>, getCapabilities, (),
+                (override));
     MOCK_METHOD(vibrator::HalResult<std::vector<int32_t>>, getVibratorIds, (), (override));
-    MOCK_METHOD(vibrator::HalResult<std::shared_ptr<vibrator::HalController>>, getVibrator,
-                (int32_t id), (override));
+    MOCK_METHOD(vibrator::HalResult<std::shared_ptr<HalController>>, getVibrator, (int32_t id),
+                (override));
     MOCK_METHOD(vibrator::HalResult<void>, prepareSynced, (const std::vector<int32_t>& ids),
                 (override));
     MOCK_METHOD(vibrator::HalResult<void>, triggerSynced,
@@ -50,13 +56,13 @@
     void SetUp() override {
         mConnectCounter = 0;
         auto callbackScheduler = std::make_shared<vibrator::CallbackScheduler>();
-        mMockHal = std::make_shared<StrictMock<MockHalWrapper>>(callbackScheduler);
-        mController = std::make_unique<
-                vibrator::HalController>(std::move(callbackScheduler),
-                                         [&](std::shared_ptr<vibrator::CallbackScheduler>) {
-                                             android_atomic_inc(&(this->mConnectCounter));
-                                             return this->mMockHal;
-                                         });
+        mMockHal = std::make_shared<StrictMock<MockManagerHalWrapper>>();
+        auto connector = [this](std::shared_ptr<vibrator::CallbackScheduler>) {
+            android_atomic_inc(&mConnectCounter);
+            return mMockHal;
+        };
+        mController = std::make_unique<vibrator::ManagerHalController>(std::move(callbackScheduler),
+                                                                       connector);
         ASSERT_NE(mController, nullptr);
     }
 
@@ -65,8 +71,7 @@
     std::shared_ptr<MockManagerHalWrapper> mMockHal;
     std::unique_ptr<vibrator::ManagerHalController> mController;
 
-    void setHalExpectations(int32_t cardinality, std::vector<int32_t> ids,
-                            vibrator::HalResult<void> voidResult,
+    void setHalExpectations(int32_t cardinality, vibrator::HalResult<void> voidResult,
                             vibrator::HalResult<vibrator::ManagerCapabilities> capabilitiesResult,
                             vibrator::HalResult<std::vector<int32_t>> idsResult,
                             vibrator::HalResult<std::shared_ptr<HalController>> vibratorResult) {
@@ -100,24 +105,20 @@
 };
 
 TEST_F(VibratorManagerHalControllerTest, TestInit) {
-    ASSERT_TRUE(mController->init());
+    mController->init();
     ASSERT_EQ(1, mConnectCounter);
 
     // Noop when wrapper was already initialized.
-    ASSERT_TRUE(mController->init());
+    mController->init();
     ASSERT_EQ(1, mConnectCounter);
 }
 
 TEST_F(VibratorManagerHalControllerTest, TestApiCallsAreForwardedToHal) {
-    std::vector<int32_t> ids;
-    ids.push_back(1);
-    ids.push_back(2);
-
-    setHalExpectations(/* cardinality= */ 1, ids, vibrator::HalResult<void>::ok(),
+    setHalExpectations(/* cardinality= */ 1, vibrator::HalResult<void>::ok(),
                        vibrator::HalResult<vibrator::ManagerCapabilities>::ok(
                                vibrator::ManagerCapabilities::SYNC),
-                       vibrator::HalResult<std::vector<int32_t>>::ok(ids),
-                       vibrator::HalResult<std::shared_ptr<vibrator::HalController>>::ok(nullptr));
+                       vibrator::HalResult<std::vector<int32_t>>::ok(VIBRATOR_IDS),
+                       vibrator::HalResult<std::shared_ptr<HalController>>::ok(nullptr));
 
     ASSERT_TRUE(mController->ping().isOk());
 
@@ -127,13 +128,13 @@
 
     auto getVibratorIdsResult = mController->getVibratorIds();
     ASSERT_TRUE(getVibratorIdsResult.isOk());
-    ASSERT_EQ(ids, getVibratorIdsResult.value());
+    ASSERT_EQ(VIBRATOR_IDS, getVibratorIdsResult.value());
 
-    auto getVibratorResult = mController->getVibrator(1);
+    auto getVibratorResult = mController->getVibrator(VIBRATOR_ID);
     ASSERT_TRUE(getVibratorResult.isOk());
     ASSERT_EQ(nullptr, getVibratorResult.value());
 
-    ASSERT_TRUE(mController->prepareSynced(ids).isOk());
+    ASSERT_TRUE(mController->prepareSynced(VIBRATOR_IDS).isOk());
     ASSERT_TRUE(mController->triggerSynced([]() {}).isOk());
     ASSERT_TRUE(mController->cancelSynced().isOk());
 
@@ -141,20 +142,18 @@
 }
 
 TEST_F(VibratorManagerHalControllerTest, TestUnsupportedApiResultDoNotResetHalConnection) {
-    std::vector<int32_t> ids;
-    setHalExpectations(/* cardinality= */ 1, ids, vibrator::HalResult<void>::unsupported(),
+    setHalExpectations(/* cardinality= */ 1, vibrator::HalResult<void>::unsupported(),
                        vibrator::HalResult<vibrator::ManagerCapabilities>::unsupported(),
                        vibrator::HalResult<std::vector<int32_t>>::unsupported(),
-                       vibrator::HalResult<
-                               std::shared_ptr<vibrator::HalController>>::unsupported());
+                       vibrator::HalResult<std::shared_ptr<HalController>>::unsupported());
 
     ASSERT_EQ(0, mConnectCounter);
 
     ASSERT_TRUE(mController->ping().isUnsupported());
     ASSERT_TRUE(mController->getCapabilities().isUnsupported());
     ASSERT_TRUE(mController->getVibratorIds().isUnsupported());
-    ASSERT_TRUE(mController->getVibrator(1).isUnsupported());
-    ASSERT_TRUE(mController->prepareSynced(ids).isUnsupported());
+    ASSERT_TRUE(mController->getVibrator(VIBRATOR_ID).isUnsupported());
+    ASSERT_TRUE(mController->prepareSynced(VIBRATOR_IDS).isUnsupported());
     ASSERT_TRUE(mController->triggerSynced([]() {}).isUnsupported());
     ASSERT_TRUE(mController->cancelSynced().isUnsupported());
 
@@ -162,20 +161,18 @@
 }
 
 TEST_F(VibratorManagerHalControllerTest, TestFailedApiResultResetsHalConnection) {
-    std::vector<int32_t> ids;
-    setHalExpectations(/* cardinality= */ 1, ids, vibrator::HalResult<void>::failed("message"),
+    setHalExpectations(MAX_ATTEMPTS, vibrator::HalResult<void>::failed("message"),
                        vibrator::HalResult<vibrator::ManagerCapabilities>::failed("message"),
                        vibrator::HalResult<std::vector<int32_t>>::failed("message"),
-                       vibrator::HalResult<std::shared_ptr<vibrator::HalController>>::failed(
-                               "message"));
+                       vibrator::HalResult<std::shared_ptr<HalController>>::failed("message"));
 
     ASSERT_EQ(0, mConnectCounter);
 
     ASSERT_TRUE(mController->ping().isFailed());
     ASSERT_TRUE(mController->getCapabilities().isFailed());
     ASSERT_TRUE(mController->getVibratorIds().isFailed());
-    ASSERT_TRUE(mController->getVibrator(1).isFailed());
-    ASSERT_TRUE(mController->prepareSynced(ids).isFailed());
+    ASSERT_TRUE(mController->getVibrator(VIBRATOR_ID).isFailed());
+    ASSERT_TRUE(mController->prepareSynced(VIBRATOR_IDS).isFailed());
     ASSERT_TRUE(mController->triggerSynced([]() {}).isFailed());
     ASSERT_TRUE(mController->cancelSynced().isFailed());