Merge "Fixing threading around mConnections in Scheduler"
diff --git a/cmds/dumpstate/DumpPool.cpp b/cmds/dumpstate/DumpPool.cpp
index e174c8e..e15ac3f 100644
--- a/cmds/dumpstate/DumpPool.cpp
+++ b/cmds/dumpstate/DumpPool.cpp
@@ -100,6 +100,10 @@
     }
 }
 
+void DumpPool::deleteTempFiles() {
+    deleteTempFiles(tmp_root_);
+}
+
 void DumpPool::setLogDuration(bool log_duration) {
     log_duration_ = log_duration;
 }
diff --git a/cmds/dumpstate/DumpPool.h b/cmds/dumpstate/DumpPool.h
index a4ea875..0c3c2cc 100644
--- a/cmds/dumpstate/DumpPool.h
+++ b/cmds/dumpstate/DumpPool.h
@@ -134,6 +134,11 @@
      */
     void waitForTask(const std::string& task_name, const std::string& title, int out_fd);
 
+    /*
+     * Deletes temporary files created by DumpPool.
+     */
+    void deleteTempFiles();
+
     static const std::string PREFIX_TMPFILE_NAME;
 
   private:
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index d108e00..c8277fe 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -2688,6 +2688,15 @@
     }
     tombstone_data_.clear();
     anr_data_.clear();
+
+    // Instead of shutdown the pool, we delete temporary files directly since
+    // shutdown blocking the call.
+    if (dump_pool_) {
+        dump_pool_->deleteTempFiles();
+    }
+    if (zip_entry_tasks_) {
+        zip_entry_tasks_->run(/*do_cancel =*/ true);
+    }
 }
 
 /*
diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp
index 3467898..67a77f6 100644
--- a/cmds/dumpsys/tests/dumpsys_test.cpp
+++ b/cmds/dumpsys/tests/dumpsys_test.cpp
@@ -55,6 +55,7 @@
     MOCK_METHOD1(listServices, Vector<String16>(int));
     MOCK_METHOD1(waitForService, sp<IBinder>(const String16&));
     MOCK_METHOD1(isDeclared, bool(const String16&));
+    MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&));
   protected:
     MOCK_METHOD0(onAsBinder, IBinder*());
 };
diff --git a/cmds/lshal/Lshal.cpp b/cmds/lshal/Lshal.cpp
index 2c3efe5..99cb93a 100644
--- a/cmds/lshal/Lshal.cpp
+++ b/cmds/lshal/Lshal.cpp
@@ -141,7 +141,7 @@
         }
     }
 
-    PipeRelay relay(out);
+    PipeRelay relay(out, err, interfaceName, instanceName);
 
     if (relay.initCheck() != OK) {
         std::string msg = "PipeRelay::initCheck() FAILED w/ " + std::to_string(relay.initCheck());
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
index 820679f..4e97636 100644
--- a/cmds/lshal/PipeRelay.cpp
+++ b/cmds/lshal/PipeRelay.cpp
@@ -23,7 +23,6 @@
 
 #include <atomic>
 
-#include <android-base/logging.h>
 #include <utils/Thread.h>
 
 namespace android {
@@ -31,8 +30,15 @@
 
 static constexpr struct timeval READ_TIMEOUT { .tv_sec = 1, .tv_usec = 0 };
 
+static std::string getThreadName(std::string interfaceName, const std::string &instanceName) {
+    auto dot = interfaceName.rfind(".");
+    if (dot != std::string::npos) interfaceName = interfaceName.substr(dot + 1);
+    return "RelayThread_" + interfaceName + "_" + instanceName;
+}
+
 struct PipeRelay::RelayThread : public Thread {
-    explicit RelayThread(int fd, std::ostream &os);
+    explicit RelayThread(int fd, std::ostream &os, const NullableOStream<std::ostream> &err,
+                         const std::string &fqName);
 
     bool threadLoop() override;
     void setFinished();
@@ -40,6 +46,7 @@
 private:
     int mFd;
     std::ostream &mOutStream;
+    NullableOStream<std::ostream> mErrStream;
 
     // If we were to use requestExit() and exitPending() instead, threadLoop()
     // may not run at all by the time ~PipeRelay is called (i.e. debug() has
@@ -47,13 +54,17 @@
     // read() are executed until data are drained.
     std::atomic_bool mFinished;
 
+    std::string mFqName;
+
     DISALLOW_COPY_AND_ASSIGN(RelayThread);
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 
-PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os)
-      : mFd(fd), mOutStream(os), mFinished(false) {}
+PipeRelay::RelayThread::RelayThread(int fd, std::ostream &os,
+                                    const NullableOStream<std::ostream> &err,
+                                    const std::string &fqName)
+      : mFd(fd), mOutStream(os), mErrStream(err), mFinished(false), mFqName(fqName) {}
 
 bool PipeRelay::RelayThread::threadLoop() {
     char buffer[1024];
@@ -66,13 +77,14 @@
 
     int res = TEMP_FAILURE_RETRY(select(mFd + 1, &set, nullptr, nullptr, &timeout));
     if (res < 0) {
-        PLOG(INFO) << "select() failed";
+        mErrStream << "debug " << mFqName << ": select() failed";
         return false;
     }
 
     if (res == 0 || !FD_ISSET(mFd, &set)) {
         if (mFinished) {
-            LOG(WARNING) << "debug: timeout reading from pipe, output may be truncated.";
+            mErrStream << "debug " << mFqName
+                       << ": timeout reading from pipe, output may be truncated.";
             return false;
         }
         // timeout, but debug() has not returned, so wait for HAL to finish.
@@ -83,7 +95,7 @@
     ssize_t n = TEMP_FAILURE_RETRY(read(mFd, buffer, sizeof(buffer)));
 
     if (n < 0) {
-        PLOG(ERROR) << "read() failed";
+        mErrStream << "debug " << mFqName << ": read() failed";
     }
 
     if (n <= 0) {
@@ -101,8 +113,9 @@
 
 ////////////////////////////////////////////////////////////////////////////////
 
-PipeRelay::PipeRelay(std::ostream &os)
-    : mInitCheck(NO_INIT) {
+PipeRelay::PipeRelay(std::ostream &os, const NullableOStream<std::ostream> &err,
+                     const std::string &interfaceName, const std::string &instanceName)
+      : mInitCheck(NO_INIT) {
     int res = pipe(mFds);
 
     if (res < 0) {
@@ -110,8 +123,8 @@
         return;
     }
 
-    mThread = new RelayThread(mFds[0], os);
-    mInitCheck = mThread->run("RelayThread");
+    mThread = new RelayThread(mFds[0], os, err, interfaceName + "/" + instanceName);
+    mInitCheck = mThread->run(getThreadName(interfaceName, instanceName).c_str());
 }
 
 void PipeRelay::CloseFd(int *fd) {
diff --git a/cmds/lshal/PipeRelay.h b/cmds/lshal/PipeRelay.h
index 835016041..bd994b4 100644
--- a/cmds/lshal/PipeRelay.h
+++ b/cmds/lshal/PipeRelay.h
@@ -21,6 +21,8 @@
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 
+#include "NullableOStream.h"
+
 namespace android {
 namespace lshal {
 
@@ -28,7 +30,10 @@
  * written to the "write"-end of the pair to the specified output stream "os".
  */
 struct PipeRelay {
-    explicit PipeRelay(std::ostream &os);
+    explicit PipeRelay(std::ostream& os,
+                       const NullableOStream<std::ostream>& err,
+                       const std::string& interfaceName,
+                       const std::string& instanceName);
     ~PipeRelay();
 
     status_t initCheck() const;
diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp
index e80c321..c8355e2 100644
--- a/cmds/servicemanager/ServiceManager.cpp
+++ b/cmds/servicemanager/ServiceManager.cpp
@@ -37,6 +37,27 @@
 namespace android {
 
 #ifndef VENDORSERVICEMANAGER
+struct ManifestWithDescription {
+    std::shared_ptr<const vintf::HalManifest> manifest;
+    const char* description;
+};
+// func true -> stop search and forEachManifest will return true
+static bool forEachManifest(const std::function<bool(const ManifestWithDescription&)>& func) {
+    for (const ManifestWithDescription& mwd : {
+            ManifestWithDescription{ vintf::VintfObject::GetDeviceHalManifest(), "device" },
+            ManifestWithDescription{ vintf::VintfObject::GetFrameworkHalManifest(), "framework" },
+        }) {
+        if (mwd.manifest == nullptr) {
+          LOG(ERROR) << "NULL VINTF MANIFEST!: " << mwd.description;
+          // note, we explicitly do not retry here, so that we can detect VINTF
+          // or other bugs (b/151696835)
+          continue;
+        }
+        if (func(mwd)) return true;
+    }
+    return false;
+}
+
 static bool isVintfDeclared(const std::string& name) {
     size_t firstSlash = name.find('/');
     size_t lastDot = name.rfind('.', firstSlash);
@@ -49,31 +70,41 @@
     const std::string iface = name.substr(lastDot+1, firstSlash-lastDot-1);
     const std::string instance = name.substr(firstSlash+1);
 
-    struct ManifestWithDescription {
-        std::shared_ptr<const vintf::HalManifest> manifest;
-        const char* description;
-    };
-    for (const ManifestWithDescription& mwd : {
-            ManifestWithDescription{ vintf::VintfObject::GetDeviceHalManifest(), "device" },
-            ManifestWithDescription{ vintf::VintfObject::GetFrameworkHalManifest(), "framework" },
-        }) {
-        if (mwd.manifest == nullptr) {
-          LOG(ERROR) << "NULL VINTF MANIFEST!: " << mwd.description;
-          // note, we explicitly do not retry here, so that we can detect VINTF
-          // or other bugs (b/151696835)
-          continue;
-        }
+    bool found = forEachManifest([&] (const ManifestWithDescription& mwd) {
         if (mwd.manifest->hasAidlInstance(package, iface, instance)) {
             LOG(INFO) << "Found " << name << " in " << mwd.description << " VINTF manifest.";
             return true;
         }
+        return false;  // continue
+    });
+
+    if (!found) {
+        // Although it is tested, explicitly rebuilding qualified name, in case it
+        // becomes something unexpected.
+        LOG(ERROR) << "Could not find " << package << "." << iface << "/" << instance
+                   << " in the VINTF manifest.";
     }
 
-    // Although it is tested, explicitly rebuilding qualified name, in case it
-    // becomes something unexpected.
-    LOG(ERROR) << "Could not find " << package << "." << iface << "/" << instance
-               << " in the VINTF manifest.";
-    return false;
+    return found;
+}
+
+static std::vector<std::string> getVintfInstances(const std::string& interface) {
+    size_t lastDot = interface.rfind('.');
+    if (lastDot == std::string::npos) {
+        LOG(ERROR) << "VINTF interfaces require names in Java package format (e.g. some.package.foo.IFoo) but got: " << interface;
+        return {};
+    }
+    const std::string package = interface.substr(0, lastDot);
+    const std::string iface = interface.substr(lastDot+1);
+
+    std::vector<std::string> ret;
+    (void)forEachManifest([&](const ManifestWithDescription& mwd) {
+        auto instances = mwd.manifest->getAidlInstances(package, iface);
+        ret.insert(ret.end(), instances.begin(), instances.end());
+        return false;  // continue
+    });
+
+    return ret;
 }
 
 static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::string& name) {
@@ -331,6 +362,30 @@
     return Status::ok();
 }
 
+binder::Status ServiceManager::getDeclaredInstances(const std::string& interface, std::vector<std::string>* outReturn) {
+    auto ctx = mAccess->getCallingContext();
+
+    std::vector<std::string> allInstances;
+#ifndef VENDORSERVICEMANAGER
+    allInstances = getVintfInstances(interface);
+#endif
+
+    outReturn->clear();
+
+    for (const std::string& instance : allInstances) {
+        // TODO(b/169275998): allow checking policy only once for the interface
+        if (mAccess->canFind(ctx, interface + "/" + instance)) {
+            outReturn->push_back(instance);
+        }
+    }
+
+    if (outReturn->size() == 0 && allInstances.size() != 0) {
+        return Status::fromExceptionCode(Status::EX_SECURITY);
+    }
+
+    return Status::ok();
+}
+
 void ServiceManager::removeRegistrationCallback(const wp<IBinder>& who,
                                     ServiceCallbackMap::iterator* it,
                                     bool* found) {
diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h
index a2fc5a8..9f43eb4 100644
--- a/cmds/servicemanager/ServiceManager.h
+++ b/cmds/servicemanager/ServiceManager.h
@@ -44,6 +44,7 @@
                                               const sp<IServiceCallback>& callback) override;
 
     binder::Status isDeclared(const std::string& name, bool* outReturn) override;
+    binder::Status getDeclaredInstances(const std::string& interface, std::vector<std::string>* outReturn) override;
     binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service,
                                           const sp<IClientCallback>& cb) override;
     binder::Status tryUnregisterService(const std::string& name, const sp<IBinder>& binder) override;
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index cf78102..ccf4dc8 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -38,7 +38,6 @@
     <!-- basic system services -->
     <feature name="android.software.connectionservice" />
     <feature name="android.software.voice_recognizers" notLowRam="true" />
-    <feature name="android.software.backup" />
     <feature name="android.software.home_screen" />
     <feature name="android.software.companion_device_setup" />
     <feature name="android.software.autofill" />
diff --git a/include/input/Input.h b/include/input/Input.h
index 258adae..7d81fed 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -141,14 +141,6 @@
 #define MAX_CONTROLLER_LEDS 4
 
 /*
- * SystemUiVisibility constants from View.
- */
-enum {
-    ASYSTEM_UI_VISIBILITY_STATUS_BAR_VISIBLE = 0,
-    ASYSTEM_UI_VISIBILITY_STATUS_BAR_HIDDEN = 0x00000001,
-};
-
-/*
  * Maximum number of pointers supported per motion event.
  * Smallest number of pointers is 1.
  * (We want at least 10 but some touch controllers obstensibly configured for 10 pointers
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 8e00969..ad0a14e 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -246,6 +246,8 @@
     /* Return a new object that has a duplicate of this channel's fd. */
     std::unique_ptr<InputChannel> dup() const;
 
+    void copyTo(InputChannel& outChannel) const;
+
     status_t readFromParcel(const android::Parcel* parcel) override;
     status_t writeToParcel(android::Parcel* parcel) const override;
 
@@ -277,6 +279,8 @@
     }
 
 private:
+    base::unique_fd dupFd() const;
+
     std::string mName;
     android::base::unique_fd mFd;
 
diff --git a/include/input/PropertyMap.h b/include/input/PropertyMap.h
index 3d04331..451918b 100644
--- a/include/input/PropertyMap.h
+++ b/include/input/PropertyMap.h
@@ -17,6 +17,7 @@
 #ifndef _UTILS_PROPERTY_MAP_H
 #define _UTILS_PROPERTY_MAP_H
 
+#include <android-base/result.h>
 #include <utils/Errors.h>
 #include <utils/KeyedVector.h>
 #include <utils/String8.h>
@@ -78,7 +79,7 @@
     inline const KeyedVector<String8, String8>& getProperties() const { return mProperties; }
 
     /* Loads a property map from a file. */
-    static status_t load(const String8& filename, PropertyMap** outMap);
+    static android::base::Result<std::unique_ptr<PropertyMap>> load(const char* filename);
 
 private:
     class Parser {
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index 16afecd..05fcc2b 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -448,6 +448,14 @@
     return mLastTransactionBinderFlags;
 }
 
+void IPCThreadState::setCallRestriction(ProcessState::CallRestriction restriction) {
+    mCallRestriction = restriction;
+}
+
+ProcessState::CallRestriction IPCThreadState::getCallRestriction() const {
+    return mCallRestriction;
+}
+
 void IPCThreadState::restoreCallingIdentity(int64_t token)
 {
     mCallingUid = (int)(token>>32);
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 9aa82d9..6d728dc 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -74,6 +74,7 @@
     Vector<String16> listServices(int dumpsysPriority) override;
     sp<IBinder> waitForService(const String16& name16) override;
     bool isDeclared(const String16& name) override;
+    Vector<String16> getDeclaredInstances(const String16& interface) override;
 
     // for legacy ABI
     const String16& getInterfaceDescriptor() const override {
@@ -373,4 +374,18 @@
     return declared;
 }
 
+Vector<String16> ServiceManagerShim::getDeclaredInstances(const String16& interface) {
+    std::vector<std::string> out;
+    if (!mTheRealServiceManager->getDeclaredInstances(String8(interface).c_str(), &out).isOk()) {
+        return {};
+    }
+
+    Vector<String16> res;
+    res.setCapacity(out.size());
+    for (const std::string& instance : out) {
+        res.push(String16(instance.c_str()));
+    }
+    return res;
+}
+
 } // namespace android
diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp
index a530565..83ca687 100644
--- a/libs/binder/ProcessState.cpp
+++ b/libs/binder/ProcessState.cpp
@@ -282,9 +282,17 @@
                 // a driver API to get a handle to the context manager with
                 // proper reference counting.
 
+                IPCThreadState* ipc = IPCThreadState::self();
+
+                CallRestriction originalCallRestriction = ipc->getCallRestriction();
+                ipc->setCallRestriction(CallRestriction::NONE);
+
                 Parcel data;
-                status_t status = IPCThreadState::self()->transact(
+                status_t status = ipc->transact(
                         0, IBinder::PING_TRANSACTION, data, nullptr, 0);
+
+                ipc->setCallRestriction(originalCallRestriction);
+
                 if (status == DEAD_OBJECT)
                    return nullptr;
             }
diff --git a/libs/binder/aidl/android/os/IServiceManager.aidl b/libs/binder/aidl/android/os/IServiceManager.aidl
index ff15460..2b1e492 100644
--- a/libs/binder/aidl/android/os/IServiceManager.aidl
+++ b/libs/binder/aidl/android/os/IServiceManager.aidl
@@ -99,6 +99,14 @@
     boolean isDeclared(@utf8InCpp String name);
 
     /**
+     * Returns all declared instances for a particular interface.
+     *
+     * For instance, if 'android.foo.IFoo/foo' is declared, and 'android.foo.IFoo' is
+     * passed here, then ["foo"] would be returned.
+     */
+    @utf8InCpp String[] getDeclaredInstances(@utf8InCpp String iface);
+
+    /**
      * Request a callback when the number of clients of the service changes.
      * Used by LazyServiceRegistrar to dynamically stop services that have no clients.
      */
diff --git a/libs/binder/fuzzer/binder.cpp b/libs/binder/fuzzer/binder.cpp
index 8c0495c..e5c6333 100644
--- a/libs/binder/fuzzer/binder.cpp
+++ b/libs/binder/fuzzer/binder.cpp
@@ -19,6 +19,8 @@
 #include "util.h"
 
 #include <android/os/IServiceManager.h>
+#include <binder/ParcelableHolder.h>
+#include <binder/PersistableBundle.h>
 
 using ::android::status_t;
 
@@ -271,5 +273,20 @@
     PARCEL_READ_NO_STATUS(uid_t, readCallingWorkSourceUid),
     PARCEL_READ_NO_STATUS(size_t, getBlobAshmemSize),
     PARCEL_READ_NO_STATUS(size_t, getOpenAshmemSize),
+
+    // additional parcelable objects defined in libbinder
+    [] (const ::android::Parcel& p, uint8_t data) {
+        using ::android::os::ParcelableHolder;
+        using ::android::Parcelable;
+        FUZZ_LOG() << "about to read ParcelableHolder using readParcelable with status";
+        Parcelable::Stability stability = Parcelable::Stability::STABILITY_LOCAL;
+        if ( (data & 1) == 1 ) {
+            stability = Parcelable::Stability::STABILITY_VINTF;
+        }
+        ParcelableHolder t = ParcelableHolder(stability);
+        status_t status = p.readParcelable(&t);
+        FUZZ_LOG() << "ParcelableHolder status: " << status;
+    },
+    PARCEL_READ_WITH_STATUS(android::os::PersistableBundle, readParcelable),
 };
 // clang-format on
diff --git a/libs/binder/include/binder/IPCThreadState.h b/libs/binder/include/binder/IPCThreadState.h
index aa256d4..49ef253 100644
--- a/libs/binder/include/binder/IPCThreadState.h
+++ b/libs/binder/include/binder/IPCThreadState.h
@@ -32,6 +32,8 @@
 class IPCThreadState
 {
 public:
+    using CallRestriction = ProcessState::CallRestriction;
+
     static  IPCThreadState*     self();
     static  IPCThreadState*     selfOrNull();  // self(), but won't instantiate
 
@@ -99,6 +101,9 @@
             void                setLastTransactionBinderFlags(int32_t flags);
             int32_t             getLastTransactionBinderFlags() const;
 
+            void                setCallRestriction(CallRestriction restriction);
+            CallRestriction     getCallRestriction() const;
+
             int64_t             clearCallingIdentity();
             // Restores PID/UID (not SID)
             void                restoreCallingIdentity(int64_t token);
@@ -157,7 +162,6 @@
             // This constant needs to be kept in sync with Binder.UNSET_WORKSOURCE from the Java
             // side.
             static const int32_t kUnsetWorkSource = -1;
-
 private:
                                 IPCThreadState();
                                 ~IPCThreadState();
@@ -204,8 +208,7 @@
             bool                mPropagateWorkSource;
             int32_t             mStrictModePolicy;
             int32_t             mLastTransactionBinderFlags;
-
-            ProcessState::CallRestriction mCallRestriction;
+            CallRestriction     mCallRestriction;
 };
 
 } // namespace android
diff --git a/libs/binder/include/binder/IServiceManager.h b/libs/binder/include/binder/IServiceManager.h
index 1d520c1..3c5ccc1 100644
--- a/libs/binder/include/binder/IServiceManager.h
+++ b/libs/binder/include/binder/IServiceManager.h
@@ -96,6 +96,11 @@
      * service.
      */
     virtual bool isDeclared(const String16& name) = 0;
+
+    /**
+     * Get all instances of a service as declared in the VINTF manifest
+     */
+    virtual Vector<String16> getDeclaredInstances(const String16& interface) = 0;
 };
 
 sp<IServiceManager> defaultServiceManager();
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 f59bb75..439b019 100644
--- a/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
+++ b/libs/binder/ndk/include_cpp/android/binder_auto_utils.h
@@ -199,6 +199,9 @@
    public:
     /**
      * Takes ownership of a.
+     *
+     * WARNING: this constructor is only expected to be used when reading a
+     *     status value. Use `ScopedAStatus::ok()` instead.
      */
     explicit ScopedAStatus(AStatus* a = nullptr) : ScopedAResource(a) {}
     ~ScopedAStatus() {}
diff --git a/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
new file mode 100644
index 0000000..6701518
--- /dev/null
+++ b/libs/binder/ndk/include_cpp/android/binder_parcelable_utils.h
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+/**
+ * @addtogroup NdkBinder
+ * @{
+ */
+
+/**
+ * @file binder_parcelable_utils.h
+ * @brief Helper for parcelable.
+ */
+
+#pragma once
+
+namespace ndk {
+// Also see Parcelable.h in libbinder.
+typedef int32_t parcelable_stability_t;
+enum {
+    STABILITY_LOCAL,
+    STABILITY_VINTF,  // corresponds to @VintfStability
+};
+}  // namespace ndk
+
+/** @} */
diff --git a/libs/binder/ndk/parcel.cpp b/libs/binder/ndk/parcel.cpp
index c33c44f..722ae23 100644
--- a/libs/binder/ndk/parcel.cpp
+++ b/libs/binder/ndk/parcel.cpp
@@ -272,7 +272,7 @@
 }
 
 binder_status_t AParcel_writeStatusHeader(AParcel* parcel, const AStatus* status) {
-    return PruneStatusT(status->get()->writeToParcel(parcel->get()));
+    return PruneStatusT(status->get().writeToParcel(parcel->get()));
 }
 binder_status_t AParcel_readStatusHeader(const AParcel* parcel, AStatus** status) {
     ::android::binder::Status bstatus;
diff --git a/libs/binder/ndk/status.cpp b/libs/binder/ndk/status.cpp
index d889593..a8ae441 100644
--- a/libs/binder/ndk/status.cpp
+++ b/libs/binder/ndk/status.cpp
@@ -23,7 +23,8 @@
 using ::android::binder::Status;
 
 AStatus* AStatus_newOk() {
-    return new AStatus();
+    static AStatus status = AStatus();
+    return &status;
 }
 
 AStatus* AStatus_fromExceptionCode(binder_exception_t exception) {
@@ -47,27 +48,27 @@
 }
 
 bool AStatus_isOk(const AStatus* status) {
-    return status->get()->isOk();
+    return status->get().isOk();
 }
 
 binder_exception_t AStatus_getExceptionCode(const AStatus* status) {
-    return PruneException(status->get()->exceptionCode());
+    return PruneException(status->get().exceptionCode());
 }
 
 int32_t AStatus_getServiceSpecificError(const AStatus* status) {
-    return status->get()->serviceSpecificErrorCode();
+    return status->get().serviceSpecificErrorCode();
 }
 
 binder_status_t AStatus_getStatus(const AStatus* status) {
-    return PruneStatusT(status->get()->transactionError());
+    return PruneStatusT(status->get().transactionError());
 }
 
 const char* AStatus_getMessage(const AStatus* status) {
-    return status->get()->exceptionMessage().c_str();
+    return status->get().exceptionMessage().c_str();
 }
 
 const char* AStatus_getDescription(const AStatus* status) {
-    android::String8 description = status->get()->toString8();
+    android::String8 description = status->get().toString8();
     char* cStr = new char[description.size() + 1];
     memcpy(cStr, description.c_str(), description.size() + 1);
     return cStr;
@@ -78,7 +79,9 @@
 }
 
 void AStatus_delete(AStatus* status) {
-    delete status;
+    if (status != AStatus_newOk()) {
+        delete status;
+    }
 }
 
 binder_status_t PruneStatusT(status_t status) {
diff --git a/libs/binder/ndk/status_internal.h b/libs/binder/ndk/status_internal.h
index f6227f7..cb96e48 100644
--- a/libs/binder/ndk/status_internal.h
+++ b/libs/binder/ndk/status_internal.h
@@ -25,8 +25,7 @@
     AStatus() {}  // ok
     explicit AStatus(::android::binder::Status&& status) : mStatus(std::move(status)) {}
 
-    ::android::binder::Status* get() { return &mStatus; }
-    const ::android::binder::Status* get() const { return &mStatus; }
+    const ::android::binder::Status& get() const { return mStatus; }
 
    private:
     ::android::binder::Status mStatus;
diff --git a/libs/binder/rust/Android.bp b/libs/binder/rust/Android.bp
index 0234820..dc8270e 100644
--- a/libs/binder/rust/Android.bp
+++ b/libs/binder/rust/Android.bp
@@ -28,11 +28,8 @@
 rust_bindgen {
     name: "libbinder_ndk_bindgen",
     crate_name: "binder_ndk_bindgen",
-    wrapper_src: "sys/BinderBindings.h",
+    wrapper_src: "sys/BinderBindings.hpp",
     source_stem: "bindings",
-    cflags: [
-        "-x c++",
-    ],
     bindgen_flags: [
         // Unfortunately the only way to specify the rust_non_exhaustive enum
         // style for a type is to make it the default
diff --git a/libs/binder/rust/sys/BinderBindings.h b/libs/binder/rust/sys/BinderBindings.hpp
similarity index 100%
rename from libs/binder/rust/sys/BinderBindings.h
rename to libs/binder/rust/sys/BinderBindings.hpp
diff --git a/libs/fakeservicemanager/ServiceManager.cpp b/libs/fakeservicemanager/ServiceManager.cpp
index 6964324..4ecbe53 100644
--- a/libs/fakeservicemanager/ServiceManager.cpp
+++ b/libs/fakeservicemanager/ServiceManager.cpp
@@ -61,4 +61,16 @@
     return mNameToService.find(name) != mNameToService.end();
 }
 
+Vector<String16> ServiceManager::getDeclaredInstances(const String16& name) {
+    Vector<String16> out;
+    const String16 prefix = name + String16("/");
+    for (const auto& [registeredName, service] : mNameToService) {
+        (void) service;
+        if (registeredName.startsWith(prefix)) {
+            out.add(String16(registeredName.string() + prefix.size()));
+        }
+    }
+    return out;
+}
+
 }  // namespace android
diff --git a/libs/fakeservicemanager/ServiceManager.h b/libs/fakeservicemanager/ServiceManager.h
index 62311d4..4ef47fb 100644
--- a/libs/fakeservicemanager/ServiceManager.h
+++ b/libs/fakeservicemanager/ServiceManager.h
@@ -30,42 +30,23 @@
 public:
     ServiceManager();
 
-    /**
-     * Equivalent of checkService.
-     */
     sp<IBinder> getService( const String16& name) const override;
 
-    /**
-     * Retrieve an existing service, non-blocking.
-     */
     sp<IBinder> checkService( const String16& name) const override;
 
-    /**
-     * Register a service.
-     */
     status_t addService(const String16& name, const sp<IBinder>& service,
                         bool allowIsolated = false,
                         int dumpsysFlags = DUMP_FLAG_PRIORITY_DEFAULT) override;
 
-    /**
-     * Return list of all existing services.
-     */
     Vector<String16> listServices(int dumpsysFlags = 0) override;
 
     IBinder* onAsBinder() override;
 
-    /**
-     * Effectively no-oped in this implementation - equivalent to checkService.
-     */
     sp<IBinder> waitForService(const String16& name) override;
 
-    /**
-     * Check if a service is declared (e.g. VINTF manifest).
-     *
-     * If this returns true, waitForService should always be able to return the
-     * service.
-     */
-     bool isDeclared(const String16& name) override;
+    bool isDeclared(const String16& name) override;
+
+    Vector<String16> getDeclaredInstances(const String16& iface) override;
 
 private:
     std::map<String16, sp<IBinder>> mNameToService;
diff --git a/libs/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index 4d306e7..ef4d870 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -68,12 +68,10 @@
 public:
     InputSurface(const sp<SurfaceControl> &sc, int width, int height) {
         mSurfaceControl = sc;
-        std::unique_ptr<InputChannel> clientChannel;
-        InputChannel::openInputChannelPair("testchannels", mServerChannel, clientChannel);
-        mClientChannel = std::move(clientChannel);
 
         mInputFlinger = getInputFlinger();
-        mInputFlinger->registerInputChannel(*mServerChannel);
+        mClientChannel = std::make_shared<InputChannel>();
+        mInputFlinger->createInputChannel("testchannels", mClientChannel.get());
 
         populateInputInfo(width, height);
 
@@ -155,7 +153,7 @@
         EXPECT_EQ(0, mev->getFlags() & VERIFIED_MOTION_EVENT_FLAGS);
     }
 
-    ~InputSurface() { mInputFlinger->unregisterInputChannel(mServerChannel->getConnectionToken()); }
+    ~InputSurface() { mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken()); }
 
     void doTransaction(std::function<void(SurfaceComposerClient::Transaction&,
                     const sp<SurfaceControl>&)> transactionBody) {
@@ -192,7 +190,7 @@
     }
 
     void populateInputInfo(int width, int height) {
-        mInputInfo.token = mServerChannel->getConnectionToken();
+        mInputInfo.token = mClientChannel->getConnectionToken();
         mInputInfo.name = "Test info";
         mInputInfo.flags = InputWindowInfo::Flag::NOT_TOUCH_MODAL;
         mInputInfo.type = InputWindowInfo::Type::BASE_APPLICATION;
@@ -219,7 +217,6 @@
     }
 public:
     sp<SurfaceControl> mSurfaceControl;
-    std::unique_ptr<InputChannel> mServerChannel;
     std::shared_ptr<InputChannel> mClientChannel;
     sp<IInputFlinger> mInputFlinger;
 
@@ -536,4 +533,73 @@
 
     surface->assertFocusChange(true);
 }
+
+TEST_F(InputSurfacesTest, rotate_surface) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->showAt(10, 10);
+    surface->doTransaction([](auto &t, auto &sc) {
+        t.setMatrix(sc, 0, 1, -1, 0); // 90 degrees
+    });
+    injectTap(8, 11);
+    surface->expectTap(1, 2);
+
+    surface->doTransaction([](auto &t, auto &sc) {
+        t.setMatrix(sc, -1, 0, 0, -1); // 180 degrees
+    });
+    injectTap(9, 8);
+    surface->expectTap(1, 2);
+
+    surface->doTransaction([](auto &t, auto &sc) {
+        t.setMatrix(sc, 0, -1, 1, 0); // 270 degrees
+    });
+    injectTap(12, 9);
+    surface->expectTap(1, 2);
+}
+
+TEST_F(InputSurfacesTest, rotate_surface_with_scale) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->showAt(10, 10);
+    surface->doTransaction([](auto &t, auto &sc) {
+        t.setMatrix(sc, 0, 2, -4, 0); // 90 degrees
+    });
+    injectTap(2, 12);
+    surface->expectTap(1, 2);
+
+    surface->doTransaction([](auto &t, auto &sc) {
+        t.setMatrix(sc, -2, 0, 0, -4); // 180 degrees
+    });
+    injectTap(8, 2);
+    surface->expectTap(1, 2);
+
+    surface->doTransaction([](auto &t, auto &sc) {
+        t.setMatrix(sc, 0, -2, 4, 0); // 270 degrees
+    });
+    injectTap(18, 8);
+    surface->expectTap(1, 2);
+}
+
+TEST_F(InputSurfacesTest, rotate_surface_with_scale_and_insets) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->mInputInfo.surfaceInset = 5;
+    surface->showAt(100, 100);
+
+    surface->doTransaction([](auto &t, auto &sc) {
+        t.setMatrix(sc, 0, 2, -4, 0); // 90 degrees
+    });
+    injectTap(40, 120);
+    surface->expectTap(5, 10);
+
+    surface->doTransaction([](auto &t, auto &sc) {
+        t.setMatrix(sc, -2, 0, 0, -4); // 180 degrees
+    });
+    injectTap(80, 40);
+    surface->expectTap(5, 10);
+
+    surface->doTransaction([](auto &t, auto &sc) {
+        t.setMatrix(sc, 0, -2, 4, 0); // 270 degrees
+    });
+    injectTap(160, 80);
+    surface->expectTap(5, 10);
+}
+
 } // namespace android::test
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 79e15c1..85df405 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -377,22 +377,16 @@
 }
 
 std::unique_ptr<InputChannel> InputChannel::dup() const {
-    android::base::unique_fd newFd(::dup(getFd()));
-    if (!newFd.ok()) {
-        ALOGE("Could not duplicate fd %i for channel %s: %s", getFd().get(), getName().c_str(),
-              strerror(errno));
-        const bool hitFdLimit = errno == EMFILE || errno == ENFILE;
-        // If this process is out of file descriptors, then throwing that might end up exploding
-        // on the other side of a binder call, which isn't really helpful.
-        // Better to just crash here and hope that the FD leak is slow.
-        // Other failures could be client errors, so we still propagate those back to the caller.
-        LOG_ALWAYS_FATAL_IF(hitFdLimit, "Too many open files, could not duplicate input channel %s",
-                            getName().c_str());
-        return nullptr;
-    }
+    base::unique_fd newFd(dupFd());
     return InputChannel::create(getName(), std::move(newFd), getConnectionToken());
 }
 
+void InputChannel::copyTo(InputChannel& outChannel) const {
+    outChannel.mName = getName();
+    outChannel.mFd = dupFd();
+    outChannel.mToken = getConnectionToken();
+}
+
 status_t InputChannel::writeToParcel(android::Parcel* parcel) const {
     if (parcel == nullptr) {
         ALOGE("%s: Null parcel", __func__);
@@ -415,6 +409,23 @@
     return mToken;
 }
 
+base::unique_fd InputChannel::dupFd() const {
+    android::base::unique_fd newFd(::dup(getFd()));
+    if (!newFd.ok()) {
+        ALOGE("Could not duplicate fd %i for channel %s: %s", getFd().get(), getName().c_str(),
+              strerror(errno));
+        const bool hitFdLimit = errno == EMFILE || errno == ENFILE;
+        // If this process is out of file descriptors, then throwing that might end up exploding
+        // on the other side of a binder call, which isn't really helpful.
+        // Better to just crash here and hope that the FD leak is slow.
+        // Other failures could be client errors, so we still propagate those back to the caller.
+        LOG_ALWAYS_FATAL_IF(hitFdLimit, "Too many open files, could not duplicate input channel %s",
+                            getName().c_str());
+        return {};
+    }
+    return newFd;
+}
+
 // --- InputPublisher ---
 
 InputPublisher::InputPublisher(const std::shared_ptr<InputChannel>& channel) : mChannel(channel) {}
diff --git a/libs/input/PropertyMap.cpp b/libs/input/PropertyMap.cpp
index 4833eb9..a842166 100644
--- a/libs/input/PropertyMap.cpp
+++ b/libs/input/PropertyMap.cpp
@@ -107,23 +107,22 @@
     }
 }
 
-status_t PropertyMap::load(const String8& filename, PropertyMap** outMap) {
-    *outMap = nullptr;
+android::base::Result<std::unique_ptr<PropertyMap>> PropertyMap::load(const char* filename) {
+    std::unique_ptr<PropertyMap> outMap = std::make_unique<PropertyMap>();
+    if (outMap == nullptr) {
+        return android::base::Error(NO_MEMORY) << "Error allocating property map.";
+    }
 
-    Tokenizer* tokenizer;
-    status_t status = Tokenizer::open(filename, &tokenizer);
+    Tokenizer* rawTokenizer;
+    status_t status = Tokenizer::open(String8(filename), &rawTokenizer);
+    std::unique_ptr<Tokenizer> tokenizer(rawTokenizer);
     if (status) {
-        ALOGE("Error %d opening property file %s.", status, filename.string());
+        ALOGE("Error %d opening property file %s.", status, filename);
     } else {
-        PropertyMap* map = new PropertyMap();
-        if (!map) {
-            ALOGE("Error allocating property map.");
-            status = NO_MEMORY;
-        } else {
 #if DEBUG_PARSER_PERFORMANCE
             nsecs_t startTime = systemTime(SYSTEM_TIME_MONOTONIC);
 #endif
-            Parser parser(map, tokenizer);
+            Parser parser(outMap.get(), tokenizer.get());
             status = parser.parse();
 #if DEBUG_PARSER_PERFORMANCE
             nsecs_t elapsedTime = systemTime(SYSTEM_TIME_MONOTONIC) - startTime;
@@ -132,14 +131,10 @@
                   elapsedTime / 1000000.0);
 #endif
             if (status) {
-                delete map;
-            } else {
-                *outMap = map;
+                return android::base::Error(BAD_VALUE) << "Could not parse " << filename;
             }
-        }
-        delete tokenizer;
     }
-    return status;
+    return std::move(outMap);
 }
 
 // --- PropertyMap::Parser ---
diff --git a/libs/input/PropertyMap_fuzz.cpp b/libs/input/PropertyMap_fuzz.cpp
index 23ead0e..afb97a1 100755
--- a/libs/input/PropertyMap_fuzz.cpp
+++ b/libs/input/PropertyMap_fuzz.cpp
@@ -42,7 +42,7 @@
                     android::String8 out;
                     propertyMap.tryGetProperty(key, out);
                 },
-                [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void {
+                [](FuzzedDataProvider* dataProvider, android::PropertyMap /*unused*/) -> void {
                     TemporaryFile tf;
                     // Generate file contents
                     std::string contents = dataProvider->ConsumeRandomLengthString(MAX_FILE_SIZE);
@@ -52,8 +52,7 @@
                         const char* bytes = contents.c_str();
                         android::base::WriteStringToFd(bytes, tf.fd);
                     }
-                    android::PropertyMap* mapPtr = &propertyMap;
-                    android::PropertyMap::load(android::String8(tf.path), &mapPtr);
+                    android::PropertyMap::load(tf.path);
                 },
                 [](FuzzedDataProvider* dataProvider, android::PropertyMap propertyMap) -> void {
                     std::string keyStr = dataProvider->ConsumeRandomLengthString(MAX_STR_LEN);
@@ -65,12 +64,12 @@
 };
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
     FuzzedDataProvider dataProvider(data, size);
-    android::PropertyMap proprtyMap = android::PropertyMap();
+    android::PropertyMap propertyMap = android::PropertyMap();
 
     int opsRun = 0;
     while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
         uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
-        operations[op](&dataProvider, proprtyMap);
+        operations[op](&dataProvider, propertyMap);
     }
     return 0;
 }
diff --git a/libs/input/android/os/IInputFlinger.aidl b/libs/input/android/os/IInputFlinger.aidl
index 0cdf0bb..1771d19 100644
--- a/libs/input/android/os/IInputFlinger.aidl
+++ b/libs/input/android/os/IInputFlinger.aidl
@@ -30,8 +30,8 @@
     // shouldn't be a concern.
     oneway void setInputWindows(in InputWindowInfo[] inputHandles,
             in @nullable ISetInputWindowsListener setInputWindowsListener);
-    void registerInputChannel(in InputChannel channel);
-    void unregisterInputChannel(in IBinder connectionToken);
+    InputChannel createInputChannel(in @utf8InCpp String name);
+    void removeInputChannel(in IBinder connectionToken);
     /**
      * Sets focus to the window identified by the token. This must be called
      * after updating any input window handles.
diff --git a/libs/nativedisplay/AChoreographer.cpp b/libs/nativedisplay/AChoreographer.cpp
index b7c5b2a..470f28f 100644
--- a/libs/nativedisplay/AChoreographer.cpp
+++ b/libs/nativedisplay/AChoreographer.cpp
@@ -455,12 +455,18 @@
 }
 void AChoreographer_routePostFrameCallback(AChoreographer* choreographer,
                                            AChoreographer_frameCallback callback, void* data) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
     return AChoreographer_postFrameCallback(choreographer, callback, data);
+#pragma clang diagnostic pop
 }
 void AChoreographer_routePostFrameCallbackDelayed(AChoreographer* choreographer,
                                                   AChoreographer_frameCallback callback, void* data,
                                                   long delayMillis) {
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
     return AChoreographer_postFrameCallbackDelayed(choreographer, callback, data, delayMillis);
+#pragma clang diagnostic pop
 }
 void AChoreographer_routePostFrameCallback64(AChoreographer* choreographer,
                                              AChoreographer_frameCallback64 callback, void* data) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.cpp b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
index 5438082..cb752b0 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.cpp
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.cpp
@@ -35,6 +35,7 @@
 
 #include <SkCanvas.h>
 #include <SkImage.h>
+#include <SkShadowUtils.h>
 #include <SkSurface.h>
 
 extern "C" EGLAPI const char* eglQueryStringImplementationANDROID(EGLDisplay dpy, EGLint name);
@@ -400,13 +401,12 @@
     const auto scaleY = static_cast<SkScalar>(display.physicalDisplay.height()) /
             static_cast<SkScalar>(display.clip.height());
     canvas->scale(scaleX, scaleY);
-    canvas->clipRect(SkRect::MakeLTRB(display.clip.left, display.clip.top, display.clip.right,
-                                      display.clip.bottom));
+    canvas->clipRect(getSkRect(display.clip));
     canvas->drawColor(0, SkBlendMode::kSrc);
     for (const auto& layer : layers) {
         SkPaint paint;
         const auto& bounds = layer->geometry.boundaries;
-        const auto dest = SkRect::MakeLTRB(bounds.left, bounds.top, bounds.right, bounds.bottom);
+        const auto dest = getSkRect(bounds);
 
         if (layer->source.buffer.buffer) {
             ATRACE_NAME("DrawImage");
@@ -442,6 +442,13 @@
         canvas->save();
         canvas->concat(getSkM44(layer->geometry.positionTransform));
 
+        if (layer->shadow.length > 0) {
+            const auto rect = layer->geometry.roundedCornersRadius > 0
+                    ? getSkRect(layer->geometry.roundedCornersCrop)
+                    : dest;
+            drawShadow(canvas, rect, layer->geometry.roundedCornersRadius, layer->shadow);
+        }
+
         if (layer->geometry.roundedCornersRadius > 0) {
             canvas->drawRRect(getRoundedRect(layer), paint);
         } else {
@@ -480,13 +487,24 @@
     return NO_ERROR;
 }
 
+inline SkRect SkiaGLRenderEngine::getSkRect(const FloatRect& rect) {
+    return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
+}
+
+inline SkRect SkiaGLRenderEngine::getSkRect(const Rect& rect) {
+    return SkRect::MakeLTRB(rect.left, rect.top, rect.right, rect.bottom);
+}
+
 inline SkRRect SkiaGLRenderEngine::getRoundedRect(const LayerSettings* layer) {
-    const auto& crop = layer->geometry.roundedCornersCrop;
-    const auto rect = SkRect::MakeLTRB(crop.left, crop.top, crop.right, crop.bottom);
+    const auto rect = getSkRect(layer->geometry.roundedCornersCrop);
     const auto cornerRadius = layer->geometry.roundedCornersRadius;
     return SkRRect::MakeRectXY(rect, cornerRadius, cornerRadius);
 }
 
+inline SkColor SkiaGLRenderEngine::getSkColor(const vec4& color) {
+    return SkColorSetARGB(color.a * 255, color.r * 255, color.g * 255, color.b * 255);
+}
+
 inline SkM44 SkiaGLRenderEngine::getSkM44(const mat4& matrix) {
     return SkM44(matrix[0][0], matrix[1][0], matrix[2][0], matrix[3][0],
                  matrix[0][1], matrix[1][1], matrix[2][1], matrix[3][1],
@@ -494,6 +512,10 @@
                  matrix[0][3], matrix[1][3], matrix[2][3], matrix[3][3]);
 }
 
+inline SkPoint3 SkiaGLRenderEngine::getSkPoint3(const vec3& vector) {
+    return SkPoint3::Make(vector.x, vector.y, vector.z);
+}
+
 size_t SkiaGLRenderEngine::getMaxTextureSize() const {
     return mGrContext->maxTextureSize();
 }
@@ -502,6 +524,22 @@
     return mGrContext->maxRenderTargetSize();
 }
 
+void SkiaGLRenderEngine::drawShadow(SkCanvas* canvas, const SkRect& casterRect, float cornerRadius,
+                                    const ShadowSettings& settings) {
+    ATRACE_CALL();
+    const float casterZ = settings.length / 2.0f;
+    const auto shadowShape = cornerRadius > 0
+            ? SkPath::RRect(SkRRect::MakeRectXY(casterRect, cornerRadius, cornerRadius))
+            : SkPath::Rect(casterRect);
+    const auto flags =
+            settings.casterIsTranslucent ? kTransparentOccluder_ShadowFlag : kNone_ShadowFlag;
+
+    SkShadowUtils::DrawShadow(canvas, shadowShape, SkPoint3::Make(0, 0, casterZ),
+                              getSkPoint3(settings.lightPos), settings.lightRadius,
+                              getSkColor(settings.ambientColor), getSkColor(settings.spotColor),
+                              flags);
+}
+
 EGLContext SkiaGLRenderEngine::createEglContext(EGLDisplay display, EGLConfig config,
                                                 EGLContext shareContext, bool useContextPriority,
                                                 Protection protection) {
diff --git a/libs/renderengine/skia/SkiaGLRenderEngine.h b/libs/renderengine/skia/SkiaGLRenderEngine.h
index 7103bbd..3da7f25 100644
--- a/libs/renderengine/skia/SkiaGLRenderEngine.h
+++ b/libs/renderengine/skia/SkiaGLRenderEngine.h
@@ -60,11 +60,17 @@
                                        Protection protection);
     static EGLSurface createPlaceholderEglPbufferSurface(EGLDisplay display, EGLConfig config,
                                                          int hwcFormat, Protection protection);
+    inline SkRect getSkRect(const FloatRect& layer);
+    inline SkRect getSkRect(const Rect& layer);
     inline SkRRect getRoundedRect(const LayerSettings* layer);
+    inline SkColor getSkColor(const vec4& color);
     inline SkM44 getSkM44(const mat4& matrix);
+    inline SkPoint3 getSkPoint3(const vec3& vector);
 
     base::unique_fd flush();
     bool waitFence(base::unique_fd fenceFd);
+    void drawShadow(SkCanvas* canvas, const SkRect& casterRect, float casterCornerRadius,
+                    const ShadowSettings& shadowSettings);
 
     EGLDisplay mEGLDisplay;
     EGLConfig mEGLConfig;
diff --git a/libs/ui/Transform.cpp b/libs/ui/Transform.cpp
index ec8a78a..cd68c1c 100644
--- a/libs/ui/Transform.cpp
+++ b/libs/ui/Transform.cpp
@@ -14,6 +14,9 @@
  * limitations under the License.
  */
 
+#undef LOG_TAG
+#define LOG_TAG "Transform"
+
 #include <math.h>
 
 #include <android-base/stringprintf.h>
@@ -132,7 +135,7 @@
 }
 
 float Transform::getScaleX() const {
-    return sqrt(dsdx() * dsdx()) + (dtdx() * dtdx());
+    return sqrt((dsdx() * dsdx()) + (dtdx() * dtdx()));
 }
 
 float Transform::getScaleY() const {
diff --git a/libs/ui/include/ui/Rect.h b/libs/ui/include/ui/Rect.h
index 6670dc0..58323e5 100644
--- a/libs/ui/include/ui/Rect.h
+++ b/libs/ui/include/ui/Rect.h
@@ -202,6 +202,15 @@
     // the input.
     Rect transform(uint32_t xform, int32_t width, int32_t height) const;
 
+    Rect scale(float scaleX, float scaleY) const {
+        return Rect(FloatRect(left * scaleX, top * scaleY, right * scaleX, bottom * scaleY));
+    }
+
+    Rect& scaleSelf(float scaleX, float scaleY) {
+        set(scale(scaleX, scaleY));
+        return *this;
+    }
+
     // this calculates (Region(*this) - exclude).bounds() efficiently
     Rect reduce(const Rect& exclude) const;
 
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 28ef77a..032dd4c 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -85,6 +85,14 @@
 }
 
 cc_test {
+    name: "Rect_test",
+    test_suites: ["device-tests"],
+    shared_libs: ["libui"],
+    srcs: ["Rect_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
+}
+
+cc_test {
     name: "Size_test",
     test_suites: ["device-tests"],
     shared_libs: ["libui"],
diff --git a/libs/ui/tests/Rect_test.cpp b/libs/ui/tests/Rect_test.cpp
new file mode 100644
index 0000000..5499a5b
--- /dev/null
+++ b/libs/ui/tests/Rect_test.cpp
@@ -0,0 +1,262 @@
+/*
+ * 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 <system/graphics.h>
+#include <ui/FloatRect.h>
+#include <ui/Point.h>
+#include <ui/Rect.h>
+#include <ui/Size.h>
+
+#include <gtest/gtest.h>
+
+namespace android::ui {
+
+TEST(RectTest, constructDefault) {
+    const Rect rect;
+    EXPECT_FALSE(rect.isValid());
+    EXPECT_TRUE(rect.isEmpty());
+}
+
+TEST(RectTest, constructFromWidthAndHeight) {
+    const Rect rect(100, 200);
+    EXPECT_TRUE(rect.isValid());
+    EXPECT_FALSE(rect.isEmpty());
+    EXPECT_EQ(0, rect.top);
+    EXPECT_EQ(0, rect.left);
+    EXPECT_EQ(100, rect.right);
+    EXPECT_EQ(200, rect.bottom);
+    EXPECT_EQ(100, rect.getWidth());
+    EXPECT_EQ(200, rect.getHeight());
+}
+
+TEST(RectTest, constructFromSize) {
+    const Rect rect(Size(100, 200));
+    EXPECT_TRUE(rect.isValid());
+    EXPECT_FALSE(rect.isEmpty());
+    EXPECT_EQ(0, rect.top);
+    EXPECT_EQ(0, rect.left);
+    EXPECT_EQ(100, rect.right);
+    EXPECT_EQ(200, rect.bottom);
+    EXPECT_EQ(100, rect.getWidth());
+    EXPECT_EQ(200, rect.getHeight());
+}
+
+TEST(RectTest, constructFromLTRB) {
+    const Rect rect(11, 12, 14, 14);
+    EXPECT_TRUE(rect.isValid());
+    EXPECT_FALSE(rect.isEmpty());
+    EXPECT_EQ(11, rect.left);
+    EXPECT_EQ(12, rect.top);
+    EXPECT_EQ(14, rect.right);
+    EXPECT_EQ(14, rect.bottom);
+    EXPECT_EQ(3, rect.getWidth());
+    EXPECT_EQ(2, rect.getHeight());
+}
+
+TEST(RectTest, constructFromPoints) {
+    const Rect rect(Point(11, 12), Point(14, 14));
+    EXPECT_TRUE(rect.isValid());
+    EXPECT_FALSE(rect.isEmpty());
+    EXPECT_EQ(11, rect.left);
+    EXPECT_EQ(12, rect.top);
+    EXPECT_EQ(14, rect.right);
+    EXPECT_EQ(14, rect.bottom);
+    EXPECT_EQ(3, rect.getWidth());
+    EXPECT_EQ(2, rect.getHeight());
+}
+
+TEST(RectTest, constructFromFloatRect) {
+    {
+        const Rect rect(FloatRect(10, 20, 30, 40));
+        EXPECT_TRUE(rect.isValid());
+        EXPECT_FALSE(rect.isEmpty());
+        EXPECT_EQ(10, rect.left);
+        EXPECT_EQ(20, rect.top);
+        EXPECT_EQ(30, rect.right);
+        EXPECT_EQ(40, rect.bottom);
+    }
+    // Construct with floating point error
+    {
+        constexpr float kError = 1e-3;
+        const Rect rect(FloatRect(10 - kError, 20 - kError, 30 - kError, 40 - kError));
+        EXPECT_TRUE(rect.isValid());
+        EXPECT_FALSE(rect.isEmpty());
+        EXPECT_EQ(10, rect.left);
+        EXPECT_EQ(20, rect.top);
+        EXPECT_EQ(30, rect.right);
+        EXPECT_EQ(40, rect.bottom);
+    }
+}
+
+TEST(RectTest, makeInvalid) {
+    Rect rect(10, 20, 60, 60);
+    EXPECT_TRUE(rect.isValid());
+    rect.makeInvalid();
+    EXPECT_FALSE(rect.isValid());
+}
+
+TEST(RectTest, clear) {
+    Rect rect(10, 20, 60, 60);
+    EXPECT_FALSE(rect.isEmpty());
+    rect.clear();
+    EXPECT_TRUE(rect.isEmpty());
+}
+
+TEST(RectTest, getSize) {
+    const Rect rect(10, 20, 60, 60);
+    EXPECT_EQ(Size(50, 40), rect.getSize());
+}
+
+TEST(RectTest, getBounds) {
+    const Rect rect(10, 20, 60, 60);
+    const Rect bounds = rect.getBounds();
+    EXPECT_EQ(0, bounds.left);
+    EXPECT_EQ(0, bounds.top);
+    EXPECT_EQ(50, bounds.right);
+    EXPECT_EQ(40, bounds.bottom);
+    EXPECT_EQ(rect.getSize(), bounds.getSize());
+}
+
+TEST(RectTest, getCornerPoints) {
+    const Rect rect(10, 20, 50, 60);
+    EXPECT_EQ(Point(10, 20), rect.leftTop());
+    EXPECT_EQ(Point(10, 60), rect.leftBottom());
+    EXPECT_EQ(Point(50, 20), rect.rightTop());
+    EXPECT_EQ(Point(50, 60), rect.rightBottom());
+}
+
+TEST(RectTest, operatorEquals) {
+    const Rect rect(10, 20, 50, 60);
+    EXPECT_EQ(rect, rect);
+    EXPECT_NE(Rect(0, 20, 50, 60), rect);
+    EXPECT_NE(Rect(10, 0, 50, 60), rect);
+    EXPECT_NE(Rect(10, 20, 0, 60), rect);
+    EXPECT_NE(Rect(10, 20, 50, 0), rect);
+}
+
+TEST(RectTest, operatorsPlusMinus) {
+    Rect rect = Rect(10, 20, 50, 60) + Point(1, 2);
+    EXPECT_EQ(Rect(11, 22, 51, 62), rect);
+    rect -= Point(1, 2);
+    EXPECT_EQ(Rect(10, 20, 50, 60), rect);
+
+    rect = Rect(10, 20, 50, 60) - Point(1, 2);
+    EXPECT_EQ(Rect(9, 18, 49, 58), rect);
+    rect += Point(1, 2);
+    EXPECT_EQ(Rect(10, 20, 50, 60), rect);
+}
+
+TEST(RectTest, scale) {
+    Rect rect(10, 20, 50, 60);
+    EXPECT_EQ(Rect(20, 60, 100, 180), rect.scale(2.f, 3.f));
+    rect.scaleSelf(2.f, 3.f);
+    EXPECT_EQ(Rect(20, 60, 100, 180), rect);
+
+    rect = Rect(10, 20, 50, 60);
+    constexpr float kError = 1e-3;
+    EXPECT_EQ(Rect(20, 60, 100, 180), rect.scale(2.f - kError, 3.f - kError));
+    rect.scaleSelf(2.f - kError, 3.f - kError);
+    EXPECT_EQ(Rect(20, 60, 100, 180), rect);
+}
+
+TEST(RectTest, inset) {
+    Rect rect(10, 20, 50, 60);
+    rect.inset(0, 0, 0, 0);
+    EXPECT_EQ(Rect(10, 20, 50, 60), rect);
+    rect.inset(1, 2, 3, 4);
+    EXPECT_EQ(Rect(11, 22, 47, 56), rect);
+}
+
+TEST(RectTest, intersect) {
+    const Rect rect(10, 20, 50, 60);
+    Rect intersection;
+
+    // Intersect with self is self
+    intersection.makeInvalid();
+    EXPECT_TRUE(rect.intersect(rect, &intersection));
+    EXPECT_EQ(Rect(10, 20, 50, 60), intersection);
+
+    // Intersect with rect contained in us
+    const Rect insideRect(11, 21, 45, 55);
+    intersection.makeInvalid();
+    EXPECT_TRUE(rect.intersect(insideRect, &intersection));
+    EXPECT_EQ(insideRect, intersection);
+
+    // Intersect with rect we are contained in
+    intersection.makeInvalid();
+    EXPECT_TRUE(insideRect.intersect(rect, &intersection));
+    EXPECT_EQ(insideRect, intersection);
+
+    // Empty intersection
+    intersection.makeInvalid();
+    EXPECT_FALSE(rect.intersect(Rect(100, 202, 150, 260), &intersection));
+    EXPECT_TRUE(intersection.isEmpty());
+
+    // Partial intersection
+    const Rect other(30, 40, 70, 80);
+    intersection.makeInvalid();
+    EXPECT_TRUE(rect.intersect(other, &intersection));
+    EXPECT_EQ(Rect(30, 40, 50, 60), intersection);
+
+    // Intersetion is commutative
+    intersection.makeInvalid();
+    EXPECT_TRUE(other.intersect(rect, &intersection));
+    EXPECT_EQ(Rect(30, 40, 50, 60), intersection);
+}
+
+TEST(RectTest, reduce) {
+    const Rect rect(10, 20, 50, 60);
+
+    // Reduce with self is empty
+    EXPECT_TRUE(rect.reduce(rect).isEmpty());
+
+    // Reduce with rect entirely inside is a noop
+    const Rect insideRect(11, 21, 45, 55);
+    EXPECT_EQ(rect, rect.reduce(insideRect));
+
+    // Reduce with rect entirely outside is empty
+    EXPECT_TRUE(insideRect.reduce(rect).isEmpty());
+
+    // Reduce with rect on the right
+    EXPECT_EQ(Rect(10, 20, 20, 60), rect.reduce(Rect(20, 0, 60, 70)));
+
+    // Reduce with rect on the left
+    EXPECT_EQ(Rect(40, 20, 50, 60), rect.reduce(Rect(0, 0, 40, 70)));
+
+    // Reduce with rect at the top
+    EXPECT_EQ(Rect(10, 40, 50, 60), rect.reduce(Rect(0, 0, 70, 40)));
+
+    // Reduce with rect at the bottom
+    EXPECT_EQ(Rect(10, 20, 50, 40), rect.reduce(Rect(0, 40, 70, 70)));
+}
+
+TEST(RectTest, transform) {
+    const int32_t width = 100, height = 200;
+    const Rect rect(1, 1, 2, 3);
+    EXPECT_EQ(Rect(98, 1, 99, 3), rect.transform(HAL_TRANSFORM_FLIP_H, width, height));
+    EXPECT_EQ(Rect(1, 197, 2, 199), rect.transform(HAL_TRANSFORM_FLIP_V, width, height));
+    EXPECT_EQ(Rect(197, 1, 199, 2), rect.transform(HAL_TRANSFORM_ROT_90, width, height));
+    EXPECT_EQ(Rect(98, 197, 99, 199), rect.transform(HAL_TRANSFORM_ROT_180, width, height));
+    EXPECT_EQ(Rect(1, 98, 3, 99), rect.transform(HAL_TRANSFORM_ROT_270, width, height));
+}
+
+TEST(RectTest, toFloatRect) {
+    const Rect rect(10, 20, 50, 60);
+    const FloatRect floatRect = rect.toFloatRect();
+    EXPECT_EQ(FloatRect(10.f, 20.f, 50.f, 60.f), floatRect);
+}
+
+} // namespace android::ui
diff --git a/libs/ui/tests/Size_test.cpp b/libs/ui/tests/Size_test.cpp
index 38f37ad..5f75aea 100644
--- a/libs/ui/tests/Size_test.cpp
+++ b/libs/ui/tests/Size_test.cpp
@@ -33,8 +33,7 @@
 
 #include <gtest/gtest.h>
 
-namespace android {
-namespace ui {
+namespace android::ui {
 
 TEST(SizeTest, BasicConstructionAndEqualityComparison) {
     Size s(123, 456);
@@ -215,5 +214,4 @@
     ClampTest(uint32_t(0), int32_t(0));
 }
 
-} // namespace ui
-} // namespace android
+} // namespace android::ui
diff --git a/libs/ui/tests/TEST_MAPPING b/libs/ui/tests/TEST_MAPPING
index 7fcd7de..eece18e 100644
--- a/libs/ui/tests/TEST_MAPPING
+++ b/libs/ui/tests/TEST_MAPPING
@@ -2,6 +2,9 @@
   "presubmit": [
     {
       "name": "Size_test"
+    },
+    {
+      "name": "Rect_test"
     }
   ]
 }
diff --git a/services/gpuservice/tests/unittests/GpuMemTest.cpp b/services/gpuservice/tests/unittests/GpuMemTest.cpp
index 45e8367..c5f8859 100644
--- a/services/gpuservice/tests/unittests/GpuMemTest.cpp
+++ b/services/gpuservice/tests/unittests/GpuMemTest.cpp
@@ -60,7 +60,7 @@
 
     void SetUp() override {
         SKIP_IF_BPF_NOT_SUPPORTED;
-        ASSERT_EQ(0, bpf::setrlimitForTest());
+        bpf::setrlimitForTest();
 
         mGpuMem = std::make_unique<GpuMem>();
         mTestableGpuMem = TestableGpuMem(mGpuMem.get());
diff --git a/services/inputflinger/InputManager.cpp b/services/inputflinger/InputManager.cpp
index 8af9bcb..3d99589 100644
--- a/services/inputflinger/InputManager.cpp
+++ b/services/inputflinger/InputManager.cpp
@@ -31,6 +31,25 @@
 
 namespace android {
 
+static int32_t exceptionCodeFromStatusT(status_t status) {
+    switch (status) {
+        case OK:
+            return binder::Status::EX_NONE;
+        case INVALID_OPERATION:
+            return binder::Status::EX_UNSUPPORTED_OPERATION;
+        case BAD_VALUE:
+        case BAD_TYPE:
+        case NAME_NOT_FOUND:
+            return binder::Status::EX_ILLEGAL_ARGUMENT;
+        case NO_INIT:
+            return binder::Status::EX_ILLEGAL_STATE;
+        case PERMISSION_DENIED:
+            return binder::Status::EX_SECURITY;
+        default:
+            return binder::Status::EX_TRANSACTION_FAILED;
+    }
+}
+
 InputManager::InputManager(
         const sp<InputReaderPolicyInterface>& readerPolicy,
         const sp<InputDispatcherPolicyInterface>& dispatcherPolicy) {
@@ -119,7 +138,7 @@
 }
 
 // Used by tests only.
-binder::Status InputManager::registerInputChannel(const InputChannel& channel) {
+binder::Status InputManager::createInputChannel(const std::string& name, InputChannel* outChannel) {
     IPCThreadState* ipc = IPCThreadState::self();
     const int uid = ipc->getCallingUid();
     if (uid != AID_SHELL && uid != AID_ROOT) {
@@ -128,12 +147,17 @@
         return binder::Status::ok();
     }
 
-    mDispatcher->registerInputChannel(channel.dup());
+    base::Result<std::unique_ptr<InputChannel>> channel = mDispatcher->createInputChannel(name);
+    if (!channel) {
+        return binder::Status::fromExceptionCode(exceptionCodeFromStatusT(channel.error().code()),
+                                                 channel.error().message().c_str());
+    }
+    (*channel)->copyTo(*outChannel);
     return binder::Status::ok();
 }
 
-binder::Status InputManager::unregisterInputChannel(const sp<IBinder>& connectionToken) {
-    mDispatcher->unregisterInputChannel(connectionToken);
+binder::Status InputManager::removeInputChannel(const sp<IBinder>& connectionToken) {
+    mDispatcher->removeInputChannel(connectionToken);
     return binder::Status::ok();
 }
 
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 35d2d58..49bea13 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -108,8 +108,8 @@
             const std::vector<InputWindowInfo>& handles,
             const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
 
-    binder::Status registerInputChannel(const InputChannel& channel) override;
-    binder::Status unregisterInputChannel(const sp<IBinder>& connectionToken) override;
+    binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override;
+    binder::Status removeInputChannel(const sp<IBinder>& connectionToken) override;
     binder::Status setFocusedWindow(const FocusRequest&) override;
 
 private:
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index b645d69..46bc055 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -129,17 +129,14 @@
 protected:
     explicit FakeInputReceiver(const sp<InputDispatcher>& dispatcher, const std::string name)
           : mDispatcher(dispatcher) {
-        std::unique_ptr<InputChannel> serverChannel, clientChannel;
-        InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
-        mServerChannel = std::move(serverChannel);
-        mClientChannel = std::move(clientChannel);
+        mClientChannel = *mDispatcher->createInputChannel(name);
         mConsumer = std::make_unique<InputConsumer>(mClientChannel);
     }
 
     virtual ~FakeInputReceiver() {}
 
     sp<InputDispatcher> mDispatcher;
-    std::shared_ptr<InputChannel> mServerChannel, mClientChannel;
+    std::shared_ptr<InputChannel> mClientChannel;
     std::unique_ptr<InputConsumer> mConsumer;
     PreallocatedInputEventFactory mEventFactory;
 };
@@ -152,14 +149,12 @@
     FakeWindowHandle(const std::shared_ptr<InputApplicationHandle>& inputApplicationHandle,
                      const sp<InputDispatcher>& dispatcher, const std::string name)
           : FakeInputReceiver(dispatcher, name), mFrame(Rect(0, 0, WIDTH, HEIGHT)) {
-        mDispatcher->registerInputChannel(mServerChannel);
-
         inputApplicationHandle->updateInfo();
         mInfo.applicationInfo = *inputApplicationHandle->getInfo();
     }
 
     virtual bool updateInfo() override {
-        mInfo.token = mServerChannel->getConnectionToken();
+        mInfo.token = mClientChannel->getConnectionToken();
         mInfo.name = "FakeWindowHandle";
         mInfo.type = InputWindowInfo::Type::APPLICATION;
         mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index a10da66..3ccb0c9 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -28,8 +28,8 @@
 // Log debug messages about the dispatch cycle.
 #define DEBUG_DISPATCH_CYCLE 0
 
-// Log debug messages about registrations.
-#define DEBUG_REGISTRATION 0
+// Log debug messages about channel creation
+#define DEBUG_CHANNEL_CREATION 0
 
 // Log debug messages about input event injection.
 #define DEBUG_INJECTION 0
@@ -351,6 +351,16 @@
     }
 }
 
+static status_t openInputChannelPair(const std::string& name,
+                                     std::shared_ptr<InputChannel>& serverChannel,
+                                     std::unique_ptr<InputChannel>& clientChannel) {
+    std::unique_ptr<InputChannel> uniqueServerChannel;
+    status_t result = InputChannel::openInputChannelPair(name, uniqueServerChannel, clientChannel);
+
+    serverChannel = std::move(uniqueServerChannel);
+    return result;
+}
+
 const char* InputDispatcher::typeToString(InputDispatcher::FocusResult result) {
     switch (result) {
         case InputDispatcher::FocusResult::OK:
@@ -412,7 +422,7 @@
 
     while (!mConnectionsByFd.empty()) {
         sp<Connection> connection = mConnectionsByFd.begin()->second;
-        unregisterInputChannel(connection->inputChannel->getConnectionToken());
+        removeInputChannel(connection->inputChannel->getConnectionToken());
     }
 }
 
@@ -507,7 +517,7 @@
     connection->responsive = false;
     // Stop waking up for this unresponsive connection
     mAnrTracker.eraseToken(connection->inputChannel->getConnectionToken());
-    onAnrLocked(connection);
+    onAnrLocked(*connection);
     return LONG_LONG_MIN;
 }
 
@@ -1108,11 +1118,17 @@
             (entry->policyFlags & POLICY_FLAG_TRUSTED) &&
             (!(entry->policyFlags & POLICY_FLAG_DISABLE_KEY_REPEAT))) {
             if (mKeyRepeatState.lastKeyEntry &&
-                mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode) {
+                mKeyRepeatState.lastKeyEntry->keyCode == entry->keyCode &&
                 // We have seen two identical key downs in a row which indicates that the device
                 // driver is automatically generating key repeats itself.  We take note of the
                 // repeat here, but we disable our own next key repeat timer since it is clear that
                 // we will not need to synthesize key repeats ourselves.
+                mKeyRepeatState.lastKeyEntry->deviceId == entry->deviceId) {
+                // Make sure we don't get key down from a different device. If a different
+                // device Id has same key pressed down, the new device Id will replace the
+                // current one to hold the key repeat with repeat count reset.
+                // In the future when got a KEY_UP on the device id, drop it and do not
+                // stop the key repeat on current device.
                 entry->repeatCount = mKeyRepeatState.lastKeyEntry->repeatCount + 1;
                 resetKeyRepeatLocked();
                 mKeyRepeatState.nextRepeatTime = LONG_LONG_MAX; // don't generate repeats ourselves
@@ -1123,6 +1139,12 @@
             }
             mKeyRepeatState.lastKeyEntry = entry;
             entry->refCount += 1;
+        } else if (entry->action == AKEY_EVENT_ACTION_UP && mKeyRepeatState.lastKeyEntry &&
+                   mKeyRepeatState.lastKeyEntry->deviceId != entry->deviceId) {
+            // The stale device releases the key, reset staleDeviceId.
+#if DEBUG_INBOUND_EVENT_DETAILS
+            ALOGD("deviceId=%d got KEY_UP as stale", entry->deviceId);
+#endif
         } else if (!entry->syntheticRepeat) {
             resetKeyRepeatLocked();
         }
@@ -2825,8 +2847,8 @@
             }
         }
 
-        // Unregister the channel.
-        d->unregisterInputChannelLocked(connection->inputChannel->getConnectionToken(), notify);
+        // Remove the channel.
+        d->removeInputChannelLocked(connection->inputChannel->getConnectionToken(), notify);
         return 0; // remove the callback
     }             // release lock
 }
@@ -4403,71 +4425,76 @@
     }
 }
 
-status_t InputDispatcher::registerInputChannel(const std::shared_ptr<InputChannel>& inputChannel) {
-#if DEBUG_REGISTRATION
-    ALOGD("channel '%s' ~ registerInputChannel", inputChannel->getName().c_str());
+base::Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputChannel(
+        const std::string& name) {
+#if DEBUG_CHANNEL_CREATION
+    ALOGD("channel '%s' ~ createInputChannel", name.c_str());
 #endif
 
+    std::shared_ptr<InputChannel> serverChannel;
+    std::unique_ptr<InputChannel> clientChannel;
+    status_t result = openInputChannelPair(name, serverChannel, clientChannel);
+
+    if (result) {
+        return base::Error(result) << "Failed to open input channel pair with name " << name;
+    }
+
     { // acquire lock
         std::scoped_lock _l(mLock);
-        sp<Connection> existingConnection = getConnectionLocked(inputChannel->getConnectionToken());
-        if (existingConnection != nullptr) {
-            ALOGW("Attempted to register already registered input channel '%s'",
-                  inputChannel->getName().c_str());
-            return BAD_VALUE;
-        }
+        sp<Connection> connection = new Connection(serverChannel, false /*monitor*/, mIdGenerator);
 
-        sp<Connection> connection = new Connection(inputChannel, false /*monitor*/, mIdGenerator);
-
-        int fd = inputChannel->getFd();
+        int fd = serverChannel->getFd();
         mConnectionsByFd[fd] = connection;
-        mInputChannelsByToken[inputChannel->getConnectionToken()] = inputChannel;
+        mInputChannelsByToken[serverChannel->getConnectionToken()] = serverChannel;
 
         mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
     } // release lock
 
     // Wake the looper because some connections have changed.
     mLooper->wake();
-    return OK;
+    return clientChannel;
 }
 
-status_t InputDispatcher::registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
-                                               int32_t displayId, bool isGestureMonitor) {
+base::Result<std::unique_ptr<InputChannel>> InputDispatcher::createInputMonitor(
+        int32_t displayId, bool isGestureMonitor, const std::string& name) {
+    std::shared_ptr<InputChannel> serverChannel;
+    std::unique_ptr<InputChannel> clientChannel;
+    status_t result = openInputChannelPair(name, serverChannel, clientChannel);
+    if (result) {
+        return base::Error(result) << "Failed to open input channel pair with name " << name;
+    }
+
     { // acquire lock
         std::scoped_lock _l(mLock);
 
         if (displayId < 0) {
-            ALOGW("Attempted to register input monitor without a specified display.");
-            return BAD_VALUE;
+            return base::Error(BAD_VALUE) << "Attempted to create input monitor with name " << name
+                                          << " without a specified display.";
         }
 
-        if (inputChannel->getConnectionToken() == nullptr) {
-            ALOGW("Attempted to register input monitor without an identifying token.");
-            return BAD_VALUE;
-        }
+        sp<Connection> connection = new Connection(serverChannel, true /*monitor*/, mIdGenerator);
 
-        sp<Connection> connection = new Connection(inputChannel, true /*monitor*/, mIdGenerator);
-
-        const int fd = inputChannel->getFd();
+        const int fd = serverChannel->getFd();
         mConnectionsByFd[fd] = connection;
-        mInputChannelsByToken[inputChannel->getConnectionToken()] = inputChannel;
+        mInputChannelsByToken[serverChannel->getConnectionToken()] = serverChannel;
 
         auto& monitorsByDisplay =
                 isGestureMonitor ? mGestureMonitorsByDisplay : mGlobalMonitorsByDisplay;
-        monitorsByDisplay[displayId].emplace_back(inputChannel);
+        monitorsByDisplay[displayId].emplace_back(serverChannel);
 
         mLooper->addFd(fd, 0, ALOOPER_EVENT_INPUT, handleReceiveCallback, this);
     }
+
     // Wake the looper because some connections have changed.
     mLooper->wake();
-    return OK;
+    return clientChannel;
 }
 
-status_t InputDispatcher::unregisterInputChannel(const sp<IBinder>& connectionToken) {
+status_t InputDispatcher::removeInputChannel(const sp<IBinder>& connectionToken) {
     { // acquire lock
         std::scoped_lock _l(mLock);
 
-        status_t status = unregisterInputChannelLocked(connectionToken, false /*notify*/);
+        status_t status = removeInputChannelLocked(connectionToken, false /*notify*/);
         if (status) {
             return status;
         }
@@ -4479,8 +4506,8 @@
     return OK;
 }
 
-status_t InputDispatcher::unregisterInputChannelLocked(const sp<IBinder>& connectionToken,
-                                                       bool notify) {
+status_t InputDispatcher::removeInputChannelLocked(const sp<IBinder>& connectionToken,
+                                                   bool notify) {
     sp<Connection> connection = getConnectionLocked(connectionToken);
     if (connection == nullptr) {
         ALOGW("Attempted to unregister already unregistered input channel");
@@ -4643,12 +4670,12 @@
     postCommandLocked(std::move(commandEntry));
 }
 
-void InputDispatcher::onAnrLocked(const sp<Connection>& connection) {
+void InputDispatcher::onAnrLocked(const Connection& connection) {
     // Since we are allowing the policy to extend the timeout, maybe the waitQueue
     // is already healthy again. Don't raise ANR in this situation
-    if (connection->waitQueue.empty()) {
+    if (connection.waitQueue.empty()) {
         ALOGI("Not raising ANR because the connection %s has recovered",
-              connection->inputChannel->getName().c_str());
+              connection.inputChannel->getName().c_str());
         return;
     }
     /**
@@ -4659,21 +4686,21 @@
      * processes the events linearly. So providing information about the oldest entry seems to be
      * most useful.
      */
-    DispatchEntry* oldestEntry = *connection->waitQueue.begin();
+    DispatchEntry* oldestEntry = *connection.waitQueue.begin();
     const nsecs_t currentWait = now() - oldestEntry->deliveryTime;
     std::string reason =
             android::base::StringPrintf("%s is not responding. Waited %" PRId64 "ms for %s",
-                                        connection->inputChannel->getName().c_str(),
+                                        connection.inputChannel->getName().c_str(),
                                         ns2ms(currentWait),
                                         oldestEntry->eventEntry->getDescription().c_str());
 
-    updateLastAnrStateLocked(getWindowHandleLocked(connection->inputChannel->getConnectionToken()),
+    updateLastAnrStateLocked(getWindowHandleLocked(connection.inputChannel->getConnectionToken()),
                              reason);
 
     std::unique_ptr<CommandEntry> commandEntry =
             std::make_unique<CommandEntry>(&InputDispatcher::doNotifyAnrLockedInterruptible);
     commandEntry->inputApplicationHandle = nullptr;
-    commandEntry->inputChannel = connection->inputChannel;
+    commandEntry->inputChannel = connection.inputChannel;
     commandEntry->reason = std::move(reason);
     postCommandLocked(std::move(commandEntry));
 }
@@ -4773,15 +4800,15 @@
 void InputDispatcher::extendAnrTimeoutsLocked(
         const std::shared_ptr<InputApplicationHandle>& application,
         const sp<IBinder>& connectionToken, std::chrono::nanoseconds timeoutExtension) {
+    if (connectionToken == nullptr && application != nullptr) {
+        // The ANR happened because there's no focused window
+        mNoFocusedWindowTimeoutTime = now() + timeoutExtension.count();
+        mAwaitedFocusedApplication = application;
+    }
+
     sp<Connection> connection = getConnectionLocked(connectionToken);
     if (connection == nullptr) {
-        if (mNoFocusedWindowTimeoutTime.has_value() && application != nullptr) {
-            // Maybe ANR happened because there's no focused window?
-            mNoFocusedWindowTimeoutTime = now() + timeoutExtension.count();
-            mAwaitedFocusedApplication = application;
-        } else {
-            // It's also possible that the connection already disappeared. No action necessary.
-        }
+        // It's possible that the connection already disappeared. No action necessary.
         return;
     }
 
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index f3b3dda..4fcdcc2 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -116,12 +116,12 @@
     virtual bool transferTouchFocus(const sp<IBinder>& fromToken,
                                     const sp<IBinder>& toToken) override;
 
-    virtual status_t registerInputChannel(
-            const std::shared_ptr<InputChannel>& inputChannel) override;
+    virtual base::Result<std::unique_ptr<InputChannel>> createInputChannel(
+            const std::string& name) override;
     virtual void setFocusedWindow(const FocusRequest&) override;
-    virtual status_t registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
-                                          int32_t displayId, bool isGestureMonitor) override;
-    virtual status_t unregisterInputChannel(const sp<IBinder>& connectionToken) override;
+    virtual base::Result<std::unique_ptr<InputChannel>> createInputMonitor(
+            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;
 
     std::array<uint8_t, 32> sign(const VerifiedInputEvent& event) const;
@@ -513,7 +513,7 @@
     void removeMonitorChannelLocked(
             const sp<IBinder>& connectionToken,
             std::unordered_map<int32_t, std::vector<Monitor>>& monitorsByDisplay) REQUIRES(mLock);
-    status_t unregisterInputChannelLocked(const sp<IBinder>& connectionToken, bool notify)
+    status_t removeInputChannelLocked(const sp<IBinder>& connectionToken, bool notify)
             REQUIRES(mLock);
 
     // Interesting events that we might like to log or tell the framework about.
@@ -525,7 +525,7 @@
                               int32_t displayId, std::string_view reason) REQUIRES(mLock);
     void notifyFocusChangedLocked(const sp<IBinder>& oldFocus, const sp<IBinder>& newFocus)
             REQUIRES(mLock);
-    void onAnrLocked(const sp<Connection>& connection) REQUIRES(mLock);
+    void onAnrLocked(const Connection& connection) REQUIRES(mLock);
     void onAnrLocked(const std::shared_ptr<InputApplicationHandle>& application) REQUIRES(mLock);
     void updateLastAnrStateLocked(const sp<InputWindowHandle>& window, const std::string& reason)
             REQUIRES(mLock);
diff --git a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
index c3d50ea..67d9a06 100644
--- a/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
+++ b/services/inputflinger/dispatcher/include/InputDispatcherInterface.h
@@ -18,6 +18,7 @@
 #define _UI_INPUT_INPUTDISPATCHER_INPUTDISPATCHERINTERFACE_H
 
 #include <InputListener.h>
+#include <android-base/result.h>
 #include <android/FocusRequest.h>
 #include <android/os/ISetInputWindowsListener.h>
 #include <input/InputApplication.h>
@@ -155,13 +156,16 @@
      */
     virtual void setFocusedWindow(const FocusRequest&) = 0;
 
-    /* Registers input channels that may be used as targets for input events.
+    /**
+     * Creates an input channel that may be used as targets for input events.
      *
      * This method may be called on any thread (usually by the input manager).
      */
-    virtual status_t registerInputChannel(const std::shared_ptr<InputChannel>& inputChannel) = 0;
+    virtual base::Result<std::unique_ptr<InputChannel>> createInputChannel(
+            const std::string& name) = 0;
 
-    /* Registers input channels to be used to monitor input events.
+    /**
+     * Creates an input channel to be used to monitor input events.
      *
      * Each monitor must target a specific display and will only receive input events sent to that
      * display. If the monitor is a gesture monitor, it will only receive pointer events on the
@@ -169,14 +173,14 @@
      *
      * This method may be called on any thread (usually by the input manager).
      */
-    virtual status_t registerInputMonitor(const std::shared_ptr<InputChannel>& inputChannel,
-                                          int32_t displayId, bool gestureMonitor) = 0;
+    virtual base::Result<std::unique_ptr<InputChannel>> createInputMonitor(
+            int32_t displayId, bool gestureMonitor, const std::string& name) = 0;
 
-    /* Unregister input channels that will no longer receive input events.
+    /* Removes input channels that will no longer receive input events.
      *
      * This method may be called on any thread (usually by the input manager).
      */
-    virtual status_t unregisterInputChannel(const sp<IBinder>& connectionToken) = 0;
+    virtual status_t removeInputChannel(const sp<IBinder>& connectionToken) = 0;
 
     /* Allows an input monitor steal the current pointer stream away from normal input windows.
      *
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
index cabc782..2ebdbcf 100644
--- a/services/inputflinger/host/InputDriver.cpp
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -36,7 +36,7 @@
 #define INDENT2 "    "
 
 struct input_property_map {
-    android::PropertyMap* propertyMap;
+    std::unique_ptr<android::PropertyMap> propertyMap;
 };
 
 struct input_property {
@@ -225,16 +225,17 @@
         ALOGD("No input device configuration file found for device '%s'.",
                 idi.name.c_str());
     } else {
-        auto propMap = new input_property_map_t();
-        status_t status = PropertyMap::load(String8(configFile.c_str()), &propMap->propertyMap);
-        if (status) {
+        std::unique_ptr<input_property_map_t> propMap = std::make_unique<input_property_map_t>();
+        android::base::Result<std::unique_ptr<PropertyMap>> result =
+                PropertyMap::load(configFile.c_str());
+        if (!result.ok()) {
             ALOGE("Error loading input device configuration file for device '%s'. "
                     "Using default configuration.",
                     idi.name.c_str());
-            delete propMap;
             return nullptr;
         }
-        return propMap;
+        propMap->propertyMap = std::move(*result);
+        return propMap.release();
     }
     return nullptr;
 }
@@ -278,7 +279,6 @@
 
 void InputDriver::inputFreeDevicePropertyMap(input_property_map_t* map) {
     if (map != nullptr) {
-        delete map->propertyMap;
         delete map;
     }
 }
diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
index 577309a..47773d9 100644
--- a/services/inputflinger/host/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -48,8 +48,10 @@
                                    const sp<ISetInputWindowsListener>&) {
         return binder::Status::ok();
     }
-    binder::Status registerInputChannel(const InputChannel&) { return binder::Status::ok(); }
-    binder::Status unregisterInputChannel(const sp<IBinder>&) { return binder::Status::ok(); }
+    binder::Status createInputChannel(const std::string&, InputChannel*) {
+        return binder::Status::ok();
+    }
+    binder::Status removeInputChannel(const sp<IBinder>&) { return binder::Status::ok(); }
     binder::Status setFocusedWindow(const FocusRequest&) { return binder::Status::ok(); }
 
 private:
diff --git a/services/inputflinger/reader/EventHub.cpp b/services/inputflinger/reader/EventHub.cpp
index 67d3cc2..c5210b5 100644
--- a/services/inputflinger/reader/EventHub.cpp
+++ b/services/inputflinger/reader/EventHub.cpp
@@ -280,14 +280,14 @@
     if (configurationFile.empty()) {
         ALOGD("No input device configuration file found for device '%s'.", identifier.name.c_str());
     } else {
-        PropertyMap* propertyMap;
-        status_t status = PropertyMap::load(String8(configurationFile.c_str()), &propertyMap);
-        if (status) {
+        android::base::Result<std::unique_ptr<PropertyMap>> propertyMap =
+                PropertyMap::load(configurationFile.c_str());
+        if (!propertyMap.ok()) {
             ALOGE("Error loading input device configuration file for device '%s'.  "
                   "Using default configuration.",
                   identifier.name.c_str());
         } else {
-            configuration = std::unique_ptr<PropertyMap>(propertyMap);
+            configuration = std::move(*propertyMap);
         }
     }
 }
diff --git a/services/inputflinger/tests/IInputFlingerQuery.aidl b/services/inputflinger/tests/IInputFlingerQuery.aidl
index b5c5c9e..5c8a8da 100644
--- a/services/inputflinger/tests/IInputFlingerQuery.aidl
+++ b/services/inputflinger/tests/IInputFlingerQuery.aidl
@@ -26,4 +26,5 @@
     void getInputWindows(out InputWindowInfo[] inputHandles);
     void getInputChannels(out InputChannel[] channels);
     void getLastFocusRequest(out FocusRequest request);
+    void resetInputManager();
 }
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index ad6a602..70f872a 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -152,6 +152,7 @@
         const std::chrono::duration waited = std::chrono::steady_clock::now() - start;
         if (mAnrApplications.empty() || mAnrWindowTokens.empty()) {
             ADD_FAILURE() << "Did not receive ANR callback";
+            return {};
         }
         // Ensure that the ANR didn't get raised too early. We can't be too strict here because
         // the dispatcher started counting before this function was called
@@ -548,10 +549,9 @@
 
 class FakeInputReceiver {
 public:
-    explicit FakeInputReceiver(const std::shared_ptr<InputChannel>& clientChannel,
-                               const std::string name)
+    explicit FakeInputReceiver(std::unique_ptr<InputChannel> clientChannel, const std::string name)
           : mName(name) {
-        mConsumer = std::make_unique<InputConsumer>(clientChannel);
+        mConsumer = std::make_unique<InputConsumer>(std::move(clientChannel));
     }
 
     InputEvent* consume() {
@@ -701,11 +701,10 @@
                      int32_t displayId, std::optional<sp<IBinder>> token = std::nullopt)
           : mName(name) {
         if (token == std::nullopt) {
-            std::unique_ptr<InputChannel> serverChannel, clientChannel;
-            InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
-            mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(clientChannel), name);
-            token = serverChannel->getConnectionToken();
-            dispatcher->registerInputChannel(std::move(serverChannel));
+            base::Result<std::unique_ptr<InputChannel>> channel =
+                    dispatcher->createInputChannel(name);
+            token = (*channel)->getConnectionToken();
+            mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(*channel), name);
         }
 
         inputApplicationHandle->updateInfo();
@@ -1653,10 +1652,9 @@
 public:
     FakeMonitorReceiver(const sp<InputDispatcher>& dispatcher, const std::string name,
                         int32_t displayId, bool isGestureMonitor = false) {
-        std::unique_ptr<InputChannel> serverChannel, clientChannel;
-        InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
-        mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(clientChannel), name);
-        dispatcher->registerInputMonitor(std::move(serverChannel), displayId, isGestureMonitor);
+        base::Result<std::unique_ptr<InputChannel>> channel =
+                dispatcher->createInputMonitor(displayId, isGestureMonitor, name);
+        mInputReceiver = std::make_unique<FakeInputReceiver>(std::move(*channel), name);
     }
 
     sp<IBinder> getToken() { return mInputReceiver->getToken(); }
@@ -2144,8 +2142,9 @@
         mWindow->consumeFocusEvent(true);
     }
 
-    void sendAndConsumeKeyDown() {
+    void sendAndConsumeKeyDown(int32_t deviceId) {
         NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_DOWN, ADISPLAY_ID_DEFAULT);
+        keyArgs.deviceId = deviceId;
         keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Otherwise it won't generate repeat event
         mDispatcher->notifyKey(&keyArgs);
 
@@ -2167,8 +2166,9 @@
         EXPECT_EQ(repeatCount, repeatKeyEvent->getRepeatCount());
     }
 
-    void sendAndConsumeKeyUp() {
+    void sendAndConsumeKeyUp(int32_t deviceId) {
         NotifyKeyArgs keyArgs = generateKeyArgs(AKEY_EVENT_ACTION_UP, ADISPLAY_ID_DEFAULT);
+        keyArgs.deviceId = deviceId;
         keyArgs.policyFlags |= POLICY_FLAG_TRUSTED; // Unless it won't generate repeat event
         mDispatcher->notifyKey(&keyArgs);
 
@@ -2179,21 +2179,59 @@
 };
 
 TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeat) {
-    sendAndConsumeKeyDown();
+    sendAndConsumeKeyDown(1 /* deviceId */);
+    for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
+        expectKeyRepeatOnce(repeatCount);
+    }
+}
+
+TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_ReceivesKeyRepeatFromTwoDevices) {
+    sendAndConsumeKeyDown(1 /* deviceId */);
+    for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
+        expectKeyRepeatOnce(repeatCount);
+    }
+    sendAndConsumeKeyDown(2 /* deviceId */);
+    /* repeatCount will start from 1 for deviceId 2 */
     for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
         expectKeyRepeatOnce(repeatCount);
     }
 }
 
 TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_StopsKeyRepeatAfterUp) {
-    sendAndConsumeKeyDown();
+    sendAndConsumeKeyDown(1 /* deviceId */);
     expectKeyRepeatOnce(1 /*repeatCount*/);
-    sendAndConsumeKeyUp();
+    sendAndConsumeKeyUp(1 /* deviceId */);
+    mWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatAfterStaleDeviceKeyUp) {
+    sendAndConsumeKeyDown(1 /* deviceId */);
+    expectKeyRepeatOnce(1 /*repeatCount*/);
+    sendAndConsumeKeyDown(2 /* deviceId */);
+    expectKeyRepeatOnce(1 /*repeatCount*/);
+    // Stale key up from device 1.
+    sendAndConsumeKeyUp(1 /* deviceId */);
+    // Device 2 is still down, keep repeating
+    expectKeyRepeatOnce(2 /*repeatCount*/);
+    expectKeyRepeatOnce(3 /*repeatCount*/);
+    // Device 2 key up
+    sendAndConsumeKeyUp(2 /* deviceId */);
+    mWindow->assertNoEvents();
+}
+
+TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_KeyRepeatStopsAfterRepeatingKeyUp) {
+    sendAndConsumeKeyDown(1 /* deviceId */);
+    expectKeyRepeatOnce(1 /*repeatCount*/);
+    sendAndConsumeKeyDown(2 /* deviceId */);
+    expectKeyRepeatOnce(1 /*repeatCount*/);
+    // Device 2 which holds the key repeating goes up, expect the repeating to stop.
+    sendAndConsumeKeyUp(2 /* deviceId */);
+    // Device 1 still holds key down, but the repeating was already stopped
     mWindow->assertNoEvents();
 }
 
 TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseEventIdFromInputDispatcher) {
-    sendAndConsumeKeyDown();
+    sendAndConsumeKeyDown(1 /* deviceId */);
     for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
         InputEvent* repeatEvent = mWindow->consume();
         ASSERT_NE(nullptr, repeatEvent) << "Didn't receive event with repeat count " << repeatCount;
@@ -2203,7 +2241,7 @@
 }
 
 TEST_F(InputDispatcherKeyRepeatTest, FocusedWindow_RepeatKeyEventsUseUniqueEventId) {
-    sendAndConsumeKeyDown();
+    sendAndConsumeKeyDown(1 /* deviceId */);
 
     std::unordered_set<int32_t> idSet;
     for (int32_t repeatCount = 1; repeatCount <= 10; ++repeatCount) {
diff --git a/services/inputflinger/tests/InputFlingerService_test.cpp b/services/inputflinger/tests/InputFlingerService_test.cpp
index 3aef1e4..c368e79 100644
--- a/services/inputflinger/tests/InputFlingerService_test.cpp
+++ b/services/inputflinger/tests/InputFlingerService_test.cpp
@@ -135,7 +135,6 @@
 
 public:
     TestInputManager(){};
-    void checkFdFlags(const android::base::unique_fd& fd);
 
     binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles);
     binder::Status getInputChannels(std::vector<::android::InputChannel>* channels);
@@ -147,10 +146,12 @@
             const std::vector<InputWindowInfo>& handles,
             const sp<ISetInputWindowsListener>& setInputWindowsListener) override;
 
-    binder::Status registerInputChannel(const InputChannel& channel) override;
-    binder::Status unregisterInputChannel(const sp<IBinder>& connectionToken) override;
+    binder::Status createInputChannel(const std::string& name, InputChannel* outChannel) override;
+    binder::Status removeInputChannel(const sp<IBinder>& connectionToken) override;
     binder::Status setFocusedWindow(const FocusRequest&) override;
 
+    void reset();
+
 private:
     mutable Mutex mLock;
     std::unordered_map<int32_t, std::vector<sp<InputWindowHandle>>> mHandlesPerDisplay;
@@ -164,6 +165,7 @@
     binder::Status getInputWindows(std::vector<::android::InputWindowInfo>* inputHandles) override;
     binder::Status getInputChannels(std::vector<::android::InputChannel>* channels) override;
     binder::Status getLastFocusRequest(FocusRequest*) override;
+    binder::Status resetInputManager() override;
 
 private:
     sp<android::TestInputManager> mManager;
@@ -182,6 +184,11 @@
     return mManager->getLastFocusRequest(request);
 }
 
+binder::Status TestInputQuery::resetInputManager() {
+    mManager->reset();
+    return binder::Status::ok();
+}
+
 binder::Status SetInputWindowsListener::onSetInputWindowsFinished() {
     if (mCbFunc != nullptr) {
         mCbFunc();
@@ -204,23 +211,21 @@
     return binder::Status::ok();
 }
 
-void TestInputManager::checkFdFlags(const android::base::unique_fd& fd) {
-    const int result = fcntl(fd, F_GETFL);
-    EXPECT_NE(result, -1);
-    EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK);
-}
-
-binder::Status TestInputManager::registerInputChannel(const InputChannel& channel) {
+binder::Status TestInputManager::createInputChannel(const std::string& name,
+                                                    InputChannel* outChannel) {
     AutoMutex _l(mLock);
-    // check Fd flags
-    checkFdFlags(channel.getFd());
+    std::unique_ptr<InputChannel> serverChannel;
+    std::unique_ptr<InputChannel> clientChannel;
+    InputChannel::openInputChannelPair(name, serverChannel, clientChannel);
 
-    mInputChannels.push_back(channel.dup());
+    clientChannel->copyTo(*outChannel);
+
+    mInputChannels.emplace_back(std::move(serverChannel));
 
     return binder::Status::ok();
 }
 
-binder::Status TestInputManager::unregisterInputChannel(const sp<IBinder>& connectionToken) {
+binder::Status TestInputManager::removeInputChannel(const sp<IBinder>& connectionToken) {
     AutoMutex _l(mLock);
 
     auto it = std::find_if(mInputChannels.begin(), mInputChannels.end(),
@@ -271,6 +276,12 @@
     return binder::Status::ok();
 }
 
+void TestInputManager::reset() {
+    mHandlesPerDisplay.clear();
+    mInputChannels.clear();
+    mFocusRequest = FocusRequest();
+}
+
 void InputFlingerServiceTest::SetUp() {
     mSetInputWindowsListener = new SetInputWindowsListener([&]() {
         std::unique_lock<std::mutex> lock(mLock);
@@ -316,7 +327,9 @@
     InitializeInputFlinger();
 }
 
-void InputFlingerServiceTest::TearDown() {}
+void InputFlingerServiceTest::TearDown() {
+    mQuery->resetInputManager();
+}
 
 void InputFlingerServiceTest::verifyInputWindowInfo(const InputWindowInfo& info) const {
     EXPECT_EQ(mInfo, info);
@@ -367,45 +380,33 @@
 }
 
 /**
- *  Test InputFlinger service interface registerInputChannel
+ *  Test InputFlinger service interface createInputChannel
  */
-TEST_F(InputFlingerServiceTest, InputWindow_RegisterInputChannel) {
-    std::unique_ptr<InputChannel> serverChannel, clientChannel;
+TEST_F(InputFlingerServiceTest, CreateInputChannelReturnsUnblockedFd) {
+    // Test that the unblocked file descriptor flag is kept across processes over binder
+    // transactions.
 
-    InputChannel::openInputChannelPair("testchannels", serverChannel, clientChannel);
-    mService->registerInputChannel(*serverChannel);
+    InputChannel channel;
+    ASSERT_TRUE(mService->createInputChannel("testchannels", &channel).isOk());
+
+    const base::unique_fd& fd = channel.getFd();
+    ASSERT_TRUE(fd.ok());
+
+    const int result = fcntl(fd, F_GETFL);
+    EXPECT_NE(result, -1);
+    EXPECT_EQ(result & O_NONBLOCK, O_NONBLOCK);
+}
+
+TEST_F(InputFlingerServiceTest, InputWindow_CreateInputChannel) {
+    InputChannel channel;
+    ASSERT_TRUE(mService->createInputChannel("testchannels", &channel).isOk());
 
     std::vector<::android::InputChannel> channels;
     mQuery->getInputChannels(&channels);
     ASSERT_EQ(channels.size(), 1UL);
-    EXPECT_EQ(channels[0], *serverChannel);
+    EXPECT_EQ(channels[0].getConnectionToken(), channel.getConnectionToken());
 
-    mService->unregisterInputChannel(serverChannel->getConnectionToken());
-    mQuery->getInputChannels(&channels);
-    EXPECT_EQ(channels.size(), 0UL);
-}
-
-/**
- *  Test InputFlinger service interface registerInputChannel with invalid cases
- */
-TEST_F(InputFlingerServiceTest, InputWindow_RegisterInputChannelInvalid) {
-    std::unique_ptr<InputChannel> serverChannel, clientChannel;
-    InputChannel::openInputChannelPair("testchannels", serverChannel, clientChannel);
-
-    std::vector<::android::InputChannel> channels;
-    mQuery->getInputChannels(&channels);
-    EXPECT_EQ(channels.size(), 0UL);
-
-    mService->registerInputChannel(InputChannel());
-    mService->unregisterInputChannel(clientChannel->getConnectionToken());
-
-    mService->registerInputChannel(*serverChannel);
-    mService->registerInputChannel(*clientChannel);
-    mQuery->getInputChannels(&channels);
-    EXPECT_EQ(channels.size(), 2UL);
-
-    mService->unregisterInputChannel(clientChannel->getConnectionToken());
-    mService->unregisterInputChannel(serverChannel->getConnectionToken());
+    mService->removeInputChannel(channel.getConnectionToken());
     mQuery->getInputChannels(&channels);
     EXPECT_EQ(channels.size(), 0UL);
 }
diff --git a/services/surfaceflinger/Android.bp b/services/surfaceflinger/Android.bp
index 7c08e11..ed0d75b 100644
--- a/services/surfaceflinger/Android.bp
+++ b/services/surfaceflinger/Android.bp
@@ -38,7 +38,6 @@
         "android.hardware.power-cpp",
         "libbase",
         "libbinder",
-        "libbufferhubqueue",
         "libcutils",
         "libEGL",
         "libfmq",
@@ -49,7 +48,6 @@
         "liblayers_proto",
         "liblog",
         "libnativewindow",
-        "libpdx_default_transport",
         "libprocessgroup",
         "libprotobuf-cpp-lite",
         "libstatslog",
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
index fc1adcc..d590f23 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/Output.h
@@ -166,7 +166,7 @@
     virtual void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
                                const Rect& orientedDisplaySpaceRect) = 0;
     // Sets the bounds to use
-    virtual void setDisplaySpaceSize(const ui::Size&) = 0;
+    virtual void setDisplaySize(const ui::Size&) = 0;
 
     // Sets the layer stack filtering settings for this output. See
     // belongsInOutput for full details.
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
index 6fe93bf..5b832a5 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/Output.h
@@ -40,7 +40,7 @@
     void setCompositionEnabled(bool) override;
     void setProjection(ui::Rotation orientation, const Rect& layerStackSpaceRect,
                        const Rect& orientedDisplaySpaceRect) override;
-    void setDisplaySpaceSize(const ui::Size&) override;
+    void setDisplaySize(const ui::Size&) override;
     void setLayerStackFilter(uint32_t layerStackId, bool isInternal) override;
 
     void setColorTransform(const compositionengine::CompositionRefreshArgs&) override;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
index f4d2b56..06e6a6f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputCompositionState.h
@@ -39,7 +39,7 @@
 namespace compositionengine::impl {
 
 struct OutputCompositionState {
-    // If false, composition will not per performed for this display
+    // If false, composition will not be performed for this display
     bool isEnabled{false};
 
     // If false, this output is not considered secure
@@ -71,6 +71,11 @@
     // match the orientation of layerStackSpace. The orientation of this space is always ROTATION_0.
     ProjectionSpace orientedDisplaySpace;
 
+    // The space of the framebuffer. Its bounds match the size of the framebuffer and its
+    // orientation matches the orientation of the display. Typically the framebuffer space will
+    // be identical to the physical display space.
+    ProjectionSpace framebufferSpace;
+
     // The space of the physical display. It is as big as the currently active display mode. The
     // content in this space can be rotated.
     ProjectionSpace displaySpace;
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
index 19025c1..d6fbd7f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/mock/Output.h
@@ -37,7 +37,7 @@
 
     MOCK_METHOD1(setCompositionEnabled, void(bool));
     MOCK_METHOD3(setProjection, void(ui::Rotation, const Rect&, const Rect&));
-    MOCK_METHOD1(setDisplaySpaceSize, void(const ui::Size&));
+    MOCK_METHOD1(setDisplaySize, void(const ui::Size&));
     MOCK_METHOD2(setLayerStackFilter, void(uint32_t, bool));
 
     MOCK_METHOD1(setColorTransform, void(const compositionengine::CompositionRefreshArgs&));
diff --git a/services/surfaceflinger/CompositionEngine/src/Display.cpp b/services/surfaceflinger/CompositionEngine/src/Display.cpp
index d201104..5459861 100644
--- a/services/surfaceflinger/CompositionEngine/src/Display.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Display.cpp
@@ -55,6 +55,7 @@
     mPowerAdvisor = args.powerAdvisor;
 
     editState().isSecure = args.isSecure;
+    editState().displaySpace.bounds = Rect(args.pixels);
 
     setLayerStackFilter(args.layerStackId,
                         args.physical ? args.physical->type == DisplayConnectionType::Internal
diff --git a/services/surfaceflinger/CompositionEngine/src/Output.cpp b/services/surfaceflinger/CompositionEngine/src/Output.cpp
index abb8769..44edb6e 100644
--- a/services/surfaceflinger/CompositionEngine/src/Output.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/Output.cpp
@@ -69,6 +69,19 @@
     return Reversed<T>(c);
 }
 
+struct ScaleVector {
+    float x;
+    float y;
+};
+
+// Returns a ScaleVector (x, y) such that from.scale(x, y) = to',
+// where to' will have the same size as "to". In the case where "from" and "to"
+// start at the origin to'=to.
+ScaleVector getScale(const Rect& from, const Rect& to) {
+    return {.x = static_cast<float>(to.width()) / from.width(),
+            .y = static_cast<float>(to.height()) / from.height()};
+}
+
 } // namespace
 
 std::shared_ptr<Output> createOutput(
@@ -110,9 +123,10 @@
     auto& outputState = editState();
 
     outputState.displaySpace.orientation = orientation;
-    // outputState.displaySpace.bounds should be already set from setDisplaySpaceSize().
+    LOG_FATAL_IF(outputState.displaySpace.bounds == Rect::INVALID_RECT,
+                 "The display bounds are unknown.");
 
-    // Compute the orientedDisplaySpace bounds
+    // Compute orientedDisplaySpace
     ui::Size orientedSize = outputState.displaySpace.bounds.getSize();
     if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
         std::swap(orientedSize.width, orientedSize.height);
@@ -129,17 +143,51 @@
     }
     outputState.displaySpace.content = rotation.transform(orientedDisplaySpaceRect);
 
+    // Compute framebufferSpace
+    outputState.framebufferSpace.orientation = orientation;
+    LOG_FATAL_IF(outputState.framebufferSpace.bounds == Rect::INVALID_RECT,
+                 "The framebuffer bounds are unknown.");
+    const auto scale =
+            getScale(outputState.framebufferSpace.bounds, outputState.displaySpace.bounds);
+    outputState.framebufferSpace.content = outputState.displaySpace.content.scale(scale.x, scale.y);
+
+    // Compute layerStackSpace
     outputState.layerStackSpace.content = layerStackSpaceRect;
     outputState.layerStackSpace.bounds = layerStackSpaceRect;
+
     outputState.transform = outputState.layerStackSpace.getTransform(outputState.displaySpace);
     outputState.needsFiltering = outputState.transform.needsBilinearFiltering();
-
     dirtyEntireOutput();
 }
 
-void Output::setDisplaySpaceSize(const ui::Size& size) {
+void Output::setDisplaySize(const ui::Size& size) {
     mRenderSurface->setDisplaySize(size);
-    editState().displaySpace.bounds = Rect(mRenderSurface->getSize());
+
+    auto& state = editState();
+
+    // Update framebuffer space
+    const Rect newBounds(size);
+    ScaleVector scale;
+    scale = getScale(state.framebufferSpace.bounds, newBounds);
+    state.framebufferSpace.bounds = newBounds;
+    state.framebufferSpace.content.scaleSelf(scale.x, scale.y);
+
+    // Update display space
+    scale = getScale(state.displaySpace.bounds, newBounds);
+    state.displaySpace.bounds = newBounds;
+    state.displaySpace.content.scaleSelf(scale.x, scale.y);
+    state.transform = state.layerStackSpace.getTransform(state.displaySpace);
+
+    // Update oriented display space
+    const auto orientation = state.displaySpace.orientation;
+    ui::Size orientedSize = size;
+    if (orientation == ui::ROTATION_90 || orientation == ui::ROTATION_270) {
+        std::swap(orientedSize.width, orientedSize.height);
+    }
+    const Rect newOrientedBounds(orientedSize);
+    scale = getScale(state.orientedDisplaySpace.bounds, newOrientedBounds);
+    state.orientedDisplaySpace.bounds = newOrientedBounds;
+    state.orientedDisplaySpace.content.scaleSelf(scale.x, scale.y);
 
     dirtyEntireOutput();
 }
@@ -247,8 +295,7 @@
 
 void Output::setRenderSurface(std::unique_ptr<compositionengine::RenderSurface> surface) {
     mRenderSurface = std::move(surface);
-    editState().displaySpace.bounds = Rect(mRenderSurface->getSize());
-
+    editState().framebufferSpace.bounds = Rect(mRenderSurface->getSize());
     dirtyEntireOutput();
 }
 
@@ -877,7 +924,7 @@
     ALOGV("hasClientComposition");
 
     renderengine::DisplaySettings clientCompositionDisplay;
-    clientCompositionDisplay.physicalDisplay = outputState.displaySpace.content;
+    clientCompositionDisplay.physicalDisplay = outputState.framebufferSpace.content;
     clientCompositionDisplay.clip = outputState.layerStackSpace.content;
     clientCompositionDisplay.orientation =
             ui::Transform::toRotationFlags(outputState.displaySpace.orientation);
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
index 776fdde..ee30ad8 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputCompositionState.cpp
@@ -39,6 +39,8 @@
     out.append("\n   ");
     dumpVal(out, "layerStackSpace", to_string(layerStackSpace));
     out.append("\n   ");
+    dumpVal(out, "framebufferSpace", to_string(framebufferSpace));
+    out.append("\n   ");
     dumpVal(out, "orientedDisplaySpace", to_string(orientedDisplaySpace));
     out.append("\n   ");
     dumpVal(out, "displaySpace", to_string(displaySpace));
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
index c01f3e0..57b399a 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputTest.cpp
@@ -248,20 +248,46 @@
 }
 
 /*
- * Output::setDisplaySpaceSize()
+ * Output::setDisplaySize()
  */
 
-TEST_F(OutputTest, setBoundsSetsSizeAndDirtiesEntireOutput) {
-    const ui::Size displaySize{200, 400};
+TEST_F(OutputTest, setDisplaySpaceSizeUpdatesOutputStateAndDirtiesEntireOutput) {
+    mOutput->editState().layerStackSpace.content = Rect(0, 0, 2000, 1000);
+    mOutput->editState().layerStackSpace.bounds = Rect(0, 0, 2000, 1000);
+    mOutput->editState().orientedDisplaySpace.content = Rect(0, 0, 1800, 900);
+    mOutput->editState().orientedDisplaySpace.bounds = Rect(0, 0, 2000, 1000);
+    mOutput->editState().framebufferSpace.content = Rect(0, 0, 900, 1800);
+    mOutput->editState().framebufferSpace.bounds = Rect(0, 0, 1000, 2000);
+    mOutput->editState().framebufferSpace.orientation = ui::ROTATION_90;
+    mOutput->editState().displaySpace.content = Rect(0, 0, 900, 1800);
+    mOutput->editState().displaySpace.bounds = Rect(0, 0, 1000, 2000);
+    mOutput->editState().displaySpace.orientation = ui::ROTATION_90;
 
-    EXPECT_CALL(*mRenderSurface, setDisplaySize(displaySize)).Times(1);
-    EXPECT_CALL(*mRenderSurface, getSize()).WillOnce(ReturnRef(displaySize));
+    const ui::Size newDisplaySize{500, 1000};
 
-    mOutput->setDisplaySpaceSize(displaySize);
+    EXPECT_CALL(*mRenderSurface, setDisplaySize(newDisplaySize)).Times(1);
 
-    EXPECT_EQ(Rect(displaySize), mOutput->getState().displaySpace.bounds);
+    mOutput->setDisplaySize(newDisplaySize);
 
-    EXPECT_THAT(mOutput->getState().dirtyRegion, RegionEq(Region(Rect(displaySize))));
+    const auto state = mOutput->getState();
+
+    const Rect displayRect(newDisplaySize);
+    EXPECT_EQ(ui::ROTATION_0, state.layerStackSpace.orientation);
+    EXPECT_EQ(Rect(0, 0, 2000, 1000), state.layerStackSpace.content);
+    EXPECT_EQ(Rect(0, 0, 2000, 1000), state.layerStackSpace.bounds);
+    EXPECT_EQ(ui::ROTATION_0, state.orientedDisplaySpace.orientation);
+    EXPECT_EQ(Rect(0, 0, 900, 450), state.orientedDisplaySpace.content);
+    EXPECT_EQ(Rect(0, 0, 1000, 500), state.orientedDisplaySpace.bounds);
+    EXPECT_EQ(displayRect, state.displaySpace.bounds);
+    EXPECT_EQ(Rect(0, 0, 450, 900), state.displaySpace.content);
+    EXPECT_EQ(ui::ROTATION_90, state.displaySpace.orientation);
+    EXPECT_EQ(displayRect, state.framebufferSpace.bounds);
+    EXPECT_EQ(Rect(0, 0, 450, 900), state.framebufferSpace.content);
+    EXPECT_EQ(ui::ROTATION_90, state.framebufferSpace.orientation);
+
+    EXPECT_EQ(state.displaySpace.content, state.transform.transform(state.layerStackSpace.content));
+
+    EXPECT_THAT(state.dirtyRegion, RegionEq(Region(displayRect)));
 }
 
 /*
@@ -422,7 +448,7 @@
 
     mOutput->setRenderSurface(std::unique_ptr<RenderSurface>(renderSurface));
 
-    EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().displaySpace.bounds);
+    EXPECT_EQ(Rect(newDisplaySize), mOutput->getState().framebufferSpace.bounds);
 }
 
 /*
@@ -2778,9 +2804,10 @@
 
         mOutput.mState.orientedDisplaySpace.content = kDefaultOutputFrame;
         mOutput.mState.layerStackSpace.content = kDefaultOutputViewport;
+        mOutput.mState.framebufferSpace.content = kDefaultOutputDestinationClip;
         mOutput.mState.displaySpace.content = kDefaultOutputDestinationClip;
-        mOutput.mState.transform = ui::Transform{kDefaultOutputOrientationFlags};
         mOutput.mState.displaySpace.orientation = kDefaultOutputOrientation;
+        mOutput.mState.transform = ui::Transform{kDefaultOutputOrientationFlags};
         mOutput.mState.dataspace = kDefaultOutputDataspace;
         mOutput.mState.colorTransformMatrix = kDefaultColorTransformMat;
         mOutput.mState.isSecure = false;
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 7df9b76..a1ccaad 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -156,7 +156,8 @@
 }
 
 void DisplayDevice::setDisplaySize(int width, int height) {
-    mCompositionDisplay->setDisplaySpaceSize(ui::Size(width, height));
+    LOG_FATAL_IF(!isVirtual(), "Changing the display size is supported only for virtual displays.");
+    mCompositionDisplay->setDisplaySize(ui::Size(width, height));
 }
 
 void DisplayDevice::setProjection(ui::Rotation orientation, Rect layerStackSpaceRect,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index b19e453..85046a4 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -2418,40 +2418,64 @@
     const float xScale = t.getScaleX();
     const float yScale = t.getScaleY();
     if (xScale != 1.0f || yScale != 1.0f) {
-        info.touchableRegion.scaleSelf(xScale, yScale);
         xSurfaceInset = std::round(xSurfaceInset * xScale);
         ySurfaceInset = std::round(ySurfaceInset * yScale);
     }
 
-    layerBounds = t.transform(layerBounds);
+    Rect transformedLayerBounds = t.transform(layerBounds);
 
     // clamp inset to layer bounds
-    xSurfaceInset = (xSurfaceInset >= 0) ? std::min(xSurfaceInset, layerBounds.getWidth() / 2) : 0;
-    ySurfaceInset = (ySurfaceInset >= 0) ? std::min(ySurfaceInset, layerBounds.getHeight() / 2) : 0;
+    xSurfaceInset = (xSurfaceInset >= 0)
+            ? std::min(xSurfaceInset, transformedLayerBounds.getWidth() / 2)
+            : 0;
+    ySurfaceInset = (ySurfaceInset >= 0)
+            ? std::min(ySurfaceInset, transformedLayerBounds.getHeight() / 2)
+            : 0;
 
     // inset while protecting from overflow TODO(b/161235021): What is going wrong
     // in the overflow scenario?
     {
     int32_t tmp;
-    if (!__builtin_add_overflow(layerBounds.left, xSurfaceInset, &tmp)) layerBounds.left = tmp;
-    if (!__builtin_sub_overflow(layerBounds.right, xSurfaceInset, &tmp)) layerBounds.right = tmp;
-    if (!__builtin_add_overflow(layerBounds.top, ySurfaceInset, &tmp)) layerBounds.top = tmp;
-    if (!__builtin_sub_overflow(layerBounds.bottom, ySurfaceInset, &tmp)) layerBounds.bottom = tmp;
+    if (!__builtin_add_overflow(transformedLayerBounds.left, xSurfaceInset, &tmp))
+        transformedLayerBounds.left = tmp;
+    if (!__builtin_sub_overflow(transformedLayerBounds.right, xSurfaceInset, &tmp))
+        transformedLayerBounds.right = tmp;
+    if (!__builtin_add_overflow(transformedLayerBounds.top, ySurfaceInset, &tmp))
+        transformedLayerBounds.top = tmp;
+    if (!__builtin_sub_overflow(transformedLayerBounds.bottom, ySurfaceInset, &tmp))
+        transformedLayerBounds.bottom = tmp;
     }
 
     // Input coordinate should match the layer bounds.
-    info.frameLeft = layerBounds.left;
-    info.frameTop = layerBounds.top;
-    info.frameRight = layerBounds.right;
-    info.frameBottom = layerBounds.bottom;
+    info.frameLeft = transformedLayerBounds.left;
+    info.frameTop = transformedLayerBounds.top;
+    info.frameRight = transformedLayerBounds.right;
+    info.frameBottom = transformedLayerBounds.bottom;
 
+    // Compute the correct transform to send to input. This will allow it to transform the
+    // input coordinates from display space into window space. Therefore, it needs to use the
+    // final layer frame to create the inverse transform. Since surface insets are added later,
+    // along with the overflow, the best way to ensure we get the correct transform is to use
+    // the final frame calculated.
+    // 1. Take the original transform set on the window and get the inverse transform. This is
+    //    used to get the final bounds in display space (ignorning the transform). Apply the
+    //    inverse transform on the layerBounds to get the untransformed frame (in display space)
+    // 2. Take the top and left of the untransformed frame to get the real position on screen.
+    //    Apply the layer transform on top/left so it includes any scale or rotation. These will
+    //    be the new translation values for the transform.
+    // 3. Update the translation of the original transform to the new translation values.
+    // 4. Send the inverse transform to input so the coordinates can be transformed back into
+    //    window space.
+    ui::Transform inverseTransform = t.inverse();
+    Rect nonTransformedBounds = inverseTransform.transform(transformedLayerBounds);
+    vec2 translation = t.transform(nonTransformedBounds.left, nonTransformedBounds.top);
     ui::Transform inputTransform(t);
-    inputTransform.set(layerBounds.left, layerBounds.top);
+    inputTransform.set(translation.x, translation.y);
     info.transform = inputTransform.inverse();
 
     // Position the touchable region relative to frame screen location and restrict it to frame
     // bounds.
-    info.touchableRegion = info.touchableRegion.translate(info.frameLeft, info.frameTop);
+    info.touchableRegion = inputTransform.transform(info.touchableRegion);
     // 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/Scheduler/EventThread.cpp b/services/surfaceflinger/Scheduler/EventThread.cpp
index 3307388..bf2a509 100644
--- a/services/surfaceflinger/Scheduler/EventThread.cpp
+++ b/services/surfaceflinger/Scheduler/EventThread.cpp
@@ -62,6 +62,8 @@
             return "VSyncRequest::None";
         case VSyncRequest::Single:
             return "VSyncRequest::Single";
+        case VSyncRequest::SingleSuppressCallback:
+            return "VSyncRequest::SingleSuppressCallback";
         default:
             return StringPrintf("VSyncRequest::Periodic{period=%d}", vsyncPeriod(request));
     }
@@ -267,6 +269,8 @@
     if (connection->vsyncRequest == VSyncRequest::None) {
         connection->vsyncRequest = VSyncRequest::Single;
         mCondition.notify_all();
+    } else if (connection->vsyncRequest == VSyncRequest::SingleSuppressCallback) {
+        connection->vsyncRequest = VSyncRequest::Single;
     }
 }
 
@@ -451,8 +455,11 @@
             switch (connection->vsyncRequest) {
                 case VSyncRequest::None:
                     return false;
-                case VSyncRequest::Single:
+                case VSyncRequest::SingleSuppressCallback:
                     connection->vsyncRequest = VSyncRequest::None;
+                    return false;
+                case VSyncRequest::Single:
+                    connection->vsyncRequest = VSyncRequest::SingleSuppressCallback;
                     return true;
                 case VSyncRequest::Periodic:
                     return true;
diff --git a/services/surfaceflinger/Scheduler/EventThread.h b/services/surfaceflinger/Scheduler/EventThread.h
index 80bd606..e42ca05 100644
--- a/services/surfaceflinger/Scheduler/EventThread.h
+++ b/services/surfaceflinger/Scheduler/EventThread.h
@@ -50,8 +50,11 @@
 using ResyncCallback = std::function<void()>;
 
 enum class VSyncRequest {
-    None = -1,
-    Single = 0,
+    None = -2,
+    // Single wakes up for the next two frames to avoid scheduler overhead
+    Single = -1,
+    // SingleSuppressCallback only wakes up for the next frame
+    SingleSuppressCallback = 0,
     Periodic = 1,
     // Subsequent values are periods.
 };
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 6a0f24a..59a2ea4 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -6189,6 +6189,11 @@
     }
 
     sp<Layer> layer = (static_cast<MonitoredProducer*>(surface.get()))->getLayer();
+    if (layer == nullptr) {
+        ALOGE("Attempt to set frame timeline vsync on a layer that no longer exists");
+        return BAD_VALUE;
+    }
+
     layer->setFrameTimelineVsync(frameTimelineVsyncId);
     return NO_ERROR;
 }
diff --git a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
index 894ee6d..d77387a 100644
--- a/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
+++ b/services/surfaceflinger/TimeStats/timestatsproto/TimeStatsHelper.cpp
@@ -112,7 +112,7 @@
     StringAppendF(&result, "displayOnTime = %" PRId64 " ms\n", displayOnTime);
     StringAppendF(&result, "displayConfigStats is as below:\n");
     for (const auto& [fps, duration] : refreshRateStats) {
-        StringAppendF(&result, "%dfps=%ldms ", fps, ns2ms(duration));
+        StringAppendF(&result, "%dfps = %ldms\n", fps, ns2ms(duration));
     }
     result.back() = '\n';
     StringAppendF(&result, "totalP2PTime = %" PRId64 " ms\n", presentToPresent.totalTime());
diff --git a/services/vibratorservice/Android.bp b/services/vibratorservice/Android.bp
index c45a1a1..fa742c5 100644
--- a/services/vibratorservice/Android.bp
+++ b/services/vibratorservice/Android.bp
@@ -19,6 +19,7 @@
         "VibratorCallbackScheduler.cpp",
         "VibratorHalController.cpp",
         "VibratorHalWrapper.cpp",
+        "VibratorManagerHalWrapper.cpp",
     ],
 
     aidl: {
diff --git a/services/vibratorservice/VibratorHalController.cpp b/services/vibratorservice/VibratorHalController.cpp
index 46175ad..e8606ca 100644
--- a/services/vibratorservice/VibratorHalController.cpp
+++ b/services/vibratorservice/VibratorHalController.cpp
@@ -46,8 +46,6 @@
 
 // -------------------------------------------------------------------------------------------------
 
-static constexpr int MAX_RETRIES = 1;
-
 std::shared_ptr<HalWrapper> HalConnector::connect(std::shared_ptr<CallbackScheduler> scheduler) {
     static bool gHalExists = true;
     if (!gHalExists) {
@@ -89,6 +87,8 @@
 
 // -------------------------------------------------------------------------------------------------
 
+static constexpr int MAX_RETRIES = 1;
+
 template <typename T>
 HalResult<T> HalController::processHalResult(HalResult<T> result, const char* functionName) {
     if (result.isFailed()) {
@@ -126,11 +126,12 @@
 
 // -------------------------------------------------------------------------------------------------
 
-void HalController::init() {
+bool HalController::init() {
     std::lock_guard<std::mutex> lock(mConnectedHalMutex);
     if (mConnectedHal == nullptr) {
         mConnectedHal = mHalConnector->connect(mCallbackScheduler);
     }
+    return mConnectedHal != nullptr;
 }
 
 HalResult<void> HalController::ping() {
diff --git a/services/vibratorservice/VibratorManagerHalWrapper.cpp b/services/vibratorservice/VibratorManagerHalWrapper.cpp
new file mode 100644
index 0000000..71955af
--- /dev/null
+++ b/services/vibratorservice/VibratorManagerHalWrapper.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VibratorManagerHalWrapper"
+
+#include <utils/Log.h>
+
+#include <vibratorservice/VibratorManagerHalWrapper.h>
+
+namespace android {
+
+namespace vibrator {
+
+constexpr int32_t SINGLE_VIBRATOR_ID = 0;
+
+HalResult<void> LegacyManagerHalWrapper::ping() {
+    return mController->ping();
+}
+
+void LegacyManagerHalWrapper::tryReconnect() {
+    mController->tryReconnect();
+}
+
+HalResult<std::vector<int32_t>> LegacyManagerHalWrapper::getVibratorIds() {
+    if (mController->init()) {
+        return HalResult<std::vector<int32_t>>::ok(std::vector<int32_t>(1, SINGLE_VIBRATOR_ID));
+    }
+    // Controller.init did not connect to any vibrator HAL service, so the device has no vibrator.
+    return HalResult<std::vector<int32_t>>::ok(std::vector<int32_t>());
+}
+
+HalResult<std::shared_ptr<HalController>> LegacyManagerHalWrapper::getVibrator(int32_t id) {
+    if (id == SINGLE_VIBRATOR_ID && mController->init()) {
+        return HalResult<std::shared_ptr<HalController>>::ok(mController);
+    }
+    // Controller.init did not connect to any vibrator HAL service, so the device has no vibrator.
+    return HalResult<std::shared_ptr<HalController>>::failed("No vibrator with id = " +
+                                                             std::to_string(id));
+}
+
+HalResult<void> LegacyManagerHalWrapper::prepareSynced(const std::vector<int32_t>&) {
+    return HalResult<void>::unsupported();
+}
+
+HalResult<void> LegacyManagerHalWrapper::triggerSynced(const std::function<void()>&) {
+    return HalResult<void>::unsupported();
+}
+
+HalResult<void> LegacyManagerHalWrapper::cancelSynced() {
+    return HalResult<void>::unsupported();
+}
+
+}; // namespace vibrator
+
+}; // namespace android
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalController.h b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
index 3b61f42..d1028a4 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalController.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalController.h
@@ -51,11 +51,19 @@
             mConnectedHal(nullptr) {}
     virtual ~HalController() = default;
 
-    void init();
+    /* Connects to the newest HAL version available, possibly waiting for the registered service to
+     * become available. This will automatically be called at the first API usage if it was not
+     * manually called beforehand. Calling this manually during the setup phase can avoid slowing
+     * the first API call later on. Returns true if any HAL version is available, false otherwise.
+     */
+    virtual bool init();
 
-    HalResult<void> ping() final override;
-    void tryReconnect() final override;
+    /* reloads HAL service instance without waiting. This relies on the HAL version found by init()
+     * to rapidly reconnect to the specific HAL service, or defers to init() if it was never called.
+     */
+    virtual void tryReconnect() override;
 
+    virtual HalResult<void> ping() override;
     HalResult<void> on(std::chrono::milliseconds timeout,
                        const std::function<void()>& completionCallback) final override;
     HalResult<void> off() final override;
diff --git a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
index 7b99bbb..bcb735d 100644
--- a/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
+++ b/services/vibratorservice/include/vibratorservice/VibratorHalWrapper.h
@@ -140,9 +140,12 @@
           : mCallbackScheduler(std::move(scheduler)) {}
     virtual ~HalWrapper() = default;
 
-    virtual HalResult<void> ping() = 0;
+    /* reloads wrapped HAL service instance without waiting. This can be used to reconnect when the
+     * service restarts, to rapidly retry after a failure.
+     */
     virtual void tryReconnect() = 0;
 
+    virtual HalResult<void> ping() = 0;
     virtual HalResult<void> on(std::chrono::milliseconds timeout,
                                const std::function<void()>& completionCallback) = 0;
     virtual HalResult<void> off() = 0;
diff --git a/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h b/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h
new file mode 100644
index 0000000..99947a5
--- /dev/null
+++ b/services/vibratorservice/include/vibratorservice/VibratorManagerHalWrapper.h
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_OS_VIBRATOR_MANAGER_HAL_WRAPPER_H
+#define ANDROID_OS_VIBRATOR_MANAGER_HAL_WRAPPER_H
+
+#include <vibratorservice/VibratorHalController.h>
+
+namespace android {
+
+namespace vibrator {
+
+// Wrapper for VibratorManager HAL handlers.
+class ManagerHalWrapper {
+public:
+    ManagerHalWrapper() = default;
+    virtual ~ManagerHalWrapper() = default;
+
+    virtual HalResult<void> ping() = 0;
+
+    /* reloads wrapped HAL service instance without waiting. This can be used to reconnect when the
+     * service restarts, to rapidly retry after a failure.
+     */
+    virtual void tryReconnect() = 0;
+
+    virtual HalResult<std::vector<int32_t>> getVibratorIds() = 0;
+    virtual HalResult<std::shared_ptr<HalController>> getVibrator(int32_t id) = 0;
+
+    virtual HalResult<void> prepareSynced(const std::vector<int32_t>& ids) = 0;
+    virtual HalResult<void> triggerSynced(const std::function<void()>& completionCallback) = 0;
+    virtual HalResult<void> cancelSynced() = 0;
+};
+
+// Wrapper for the VibratorManager over single Vibrator HAL.
+class LegacyManagerHalWrapper : public ManagerHalWrapper {
+public:
+    LegacyManagerHalWrapper() : LegacyManagerHalWrapper(std::make_shared<HalController>()) {}
+    explicit LegacyManagerHalWrapper(std::shared_ptr<HalController> controller)
+          : mController(std::move(controller)) {}
+    virtual ~LegacyManagerHalWrapper() = default;
+
+    HalResult<void> ping() override final;
+    void tryReconnect() override final;
+
+    HalResult<std::vector<int32_t>> getVibratorIds() override final;
+    HalResult<std::shared_ptr<HalController>> getVibrator(int32_t id) override final;
+
+    HalResult<void> prepareSynced(const std::vector<int32_t>& ids) override final;
+    HalResult<void> triggerSynced(const std::function<void()>& completionCallback) override final;
+    HalResult<void> cancelSynced() override final;
+
+private:
+    const std::shared_ptr<HalController> mController;
+};
+
+}; // namespace vibrator
+
+}; // namespace android
+
+#endif // ANDROID_OS_VIBRATOR_MANAGER_HAL_WRAPPER_H
diff --git a/services/vibratorservice/test/Android.bp b/services/vibratorservice/test/Android.bp
index 9033124..5fc6d45 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",
+        "VibratorManagerHalWrapperLegacyTest.cpp",
     ],
     cflags: [
         "-Wall",
diff --git a/services/vibratorservice/test/VibratorHalControllerTest.cpp b/services/vibratorservice/test/VibratorHalControllerTest.cpp
index f04e016..cda5e9a 100644
--- a/services/vibratorservice/test/VibratorHalControllerTest.cpp
+++ b/services/vibratorservice/test/VibratorHalControllerTest.cpp
@@ -184,11 +184,11 @@
 // -------------------------------------------------------------------------------------------------
 
 TEST_F(VibratorHalControllerTest, TestInit) {
-    mController->init();
+    ASSERT_TRUE(mController->init());
     ASSERT_EQ(1, mConnectCounter);
 
     // Noop when wrapper was already initialized.
-    mController->init();
+    ASSERT_TRUE(mController->init());
     ASSERT_EQ(1, mConnectCounter);
 }
 
@@ -339,6 +339,7 @@
             std::make_unique<vibrator::HalController>(std::move(failingHalConnector), nullptr);
     ASSERT_EQ(0, mConnectCounter);
 
+    ASSERT_FALSE(mController->init());
     ASSERT_TRUE(mController->ping().isUnsupported());
     ASSERT_TRUE(mController->on(10ms, []() {}).isUnsupported());
     ASSERT_TRUE(mController->off().isUnsupported());
@@ -356,7 +357,7 @@
                         .isUnsupported());
 
     // One connection attempt per api call.
-    ASSERT_EQ(12, mConnectCounter);
+    ASSERT_EQ(13, mConnectCounter);
 }
 
 TEST_F(VibratorHalControllerTest, TestScheduledCallbackSurvivesReconnection) {
diff --git a/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp b/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp
new file mode 100644
index 0000000..d5520a1
--- /dev/null
+++ b/services/vibratorservice/test/VibratorManagerHalWrapperLegacyTest.cpp
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *            http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define LOG_TAG "VibratorManagerHalWrapperLegacyTest"
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <utils/Log.h>
+
+#include <vibratorservice/VibratorManagerHalWrapper.h>
+
+using android::hardware::vibrator::CompositeEffect;
+using android::hardware::vibrator::CompositePrimitive;
+using android::hardware::vibrator::Effect;
+using android::hardware::vibrator::EffectStrength;
+
+using std::chrono::milliseconds;
+
+using namespace android;
+using namespace testing;
+
+// -------------------------------------------------------------------------------------------------
+
+class MockHalController : public vibrator::HalController {
+public:
+    MockHalController() = default;
+    virtual ~MockHalController() = default;
+
+    MOCK_METHOD(bool, init, (), (override));
+    MOCK_METHOD(vibrator::HalResult<void>, ping, (), (override));
+    MOCK_METHOD(void, tryReconnect, (), (override));
+};
+
+// -------------------------------------------------------------------------------------------------
+
+class VibratorManagerHalWrapperLegacyTest : public Test {
+public:
+    void SetUp() override {
+        mMockController = std::make_shared<StrictMock<MockHalController>>();
+        mWrapper = std::make_unique<vibrator::LegacyManagerHalWrapper>(mMockController);
+        ASSERT_NE(mWrapper, nullptr);
+    }
+
+protected:
+    std::shared_ptr<StrictMock<MockHalController>> mMockController = nullptr;
+    std::unique_ptr<vibrator::ManagerHalWrapper> mWrapper = nullptr;
+};
+
+// -------------------------------------------------------------------------------------------------
+
+TEST_F(VibratorManagerHalWrapperLegacyTest, TestPing) {
+    EXPECT_CALL(*mMockController.get(), ping())
+            .Times(Exactly(2))
+            .WillOnce(Return(vibrator::HalResult<void>::failed("message")))
+            .WillRepeatedly(Return(vibrator::HalResult<void>::ok()));
+
+    ASSERT_TRUE(mWrapper->ping().isFailed());
+    ASSERT_TRUE(mWrapper->ping().isOk());
+}
+
+TEST_F(VibratorManagerHalWrapperLegacyTest, TestTryReconnect) {
+    EXPECT_CALL(*mMockController.get(), tryReconnect()).Times(Exactly(1));
+
+    mWrapper->tryReconnect();
+}
+
+TEST_F(VibratorManagerHalWrapperLegacyTest, TestGetVibratorIds) {
+    std::vector<int32_t> expectedIds;
+    expectedIds.push_back(0);
+
+    EXPECT_CALL(*mMockController.get(), init())
+            .Times(Exactly(2))
+            .WillOnce(Return(false))
+            .WillRepeatedly(Return(true));
+
+    auto result = mWrapper->getVibratorIds();
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(std::vector<int32_t>(), result.value());
+
+    result = mWrapper->getVibratorIds();
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(expectedIds, result.value());
+}
+
+TEST_F(VibratorManagerHalWrapperLegacyTest, TestGetVibratorWithValidIdReturnsController) {
+    EXPECT_CALL(*mMockController.get(), init())
+            .Times(Exactly(2))
+            .WillOnce(Return(false))
+            .WillRepeatedly(Return(true));
+
+    ASSERT_TRUE(mWrapper->getVibrator(0).isFailed());
+
+    auto result = mWrapper->getVibrator(0);
+    ASSERT_TRUE(result.isOk());
+    ASSERT_EQ(mMockController.get(), result.value().get());
+}
+
+TEST_F(VibratorManagerHalWrapperLegacyTest, TestGetVibratorWithInvalidIdFails) {
+    ASSERT_TRUE(mWrapper->getVibrator(-1).isFailed());
+}
+
+TEST_F(VibratorManagerHalWrapperLegacyTest, TestSyncedOperationsUnsupported) {
+    std::vector<int32_t> vibratorIds;
+    vibratorIds.push_back(0);
+
+    ASSERT_TRUE(mWrapper->prepareSynced(vibratorIds).isUnsupported());
+    ASSERT_TRUE(mWrapper->triggerSynced([]() {}).isUnsupported());
+    ASSERT_TRUE(mWrapper->cancelSynced().isUnsupported());
+}
diff --git a/vulkan/libvulkan/swapchain.cpp b/vulkan/libvulkan/swapchain.cpp
index 0f791c9..48090af 100644
--- a/vulkan/libvulkan/swapchain.cpp
+++ b/vulkan/libvulkan/swapchain.cpp
@@ -258,7 +258,11 @@
     bool shared;
 
     struct Image {
-        Image() : image(VK_NULL_HANDLE), dequeue_fence(-1), dequeued(false) {}
+        Image()
+            : image(VK_NULL_HANDLE),
+              dequeue_fence(-1),
+              release_fence(-1),
+              dequeued(false) {}
         VkImage image;
         android::sp<ANativeWindowBuffer> buffer;
         // The fence is only valid when the buffer is dequeued, and should be
@@ -266,6 +270,10 @@
         // closed: either by closing it explicitly when queueing the buffer,
         // or by passing ownership e.g. to ANativeWindow::cancelBuffer().
         int dequeue_fence;
+        // This fence is a dup of the sync fd returned from the driver via
+        // vkQueueSignalReleaseImageANDROID upon vkQueuePresentKHR. We must
+        // ensure it is closed upon re-presenting or releasing the image.
+        int release_fence;
         bool dequeued;
     } images[android::BufferQueueDefs::NUM_BUFFER_SLOTS];
 
@@ -280,10 +288,19 @@
     return reinterpret_cast<Swapchain*>(handle);
 }
 
+static bool IsFencePending(int fd) {
+    if (fd < 0)
+        return false;
+
+    errno = 0;
+    return sync_wait(fd, 0 /* timeout */) == -1 && errno == ETIME;
+}
+
 void ReleaseSwapchainImage(VkDevice device,
                            ANativeWindow* window,
                            int release_fence,
-                           Swapchain::Image& image) {
+                           Swapchain::Image& image,
+                           bool defer_if_pending) {
     ATRACE_CALL();
 
     ALOG_ASSERT(release_fence == -1 || image.dequeued,
@@ -319,10 +336,18 @@
                 close(release_fence);
             }
         }
-
+        release_fence = -1;
         image.dequeued = false;
     }
 
+    if (defer_if_pending && IsFencePending(image.release_fence))
+        return;
+
+    if (image.release_fence >= 0) {
+        close(image.release_fence);
+        image.release_fence = -1;
+    }
+
     if (image.image) {
         ATRACE_BEGIN("DestroyImage");
         GetData(device).driver.DestroyImage(device, image.image, nullptr);
@@ -338,7 +363,8 @@
         return;
     for (uint32_t i = 0; i < swapchain->num_images; i++) {
         if (!swapchain->images[i].dequeued)
-            ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i]);
+            ReleaseSwapchainImage(device, nullptr, -1, swapchain->images[i],
+                                  true);
     }
     swapchain->surface.swapchain_handle = VK_NULL_HANDLE;
     swapchain->timing.clear();
@@ -996,7 +1022,7 @@
     }
 
     for (uint32_t i = 0; i < swapchain->num_images; i++) {
-        ReleaseSwapchainImage(device, window, -1, swapchain->images[i]);
+        ReleaseSwapchainImage(device, window, -1, swapchain->images[i], false);
     }
 
     if (active) {
@@ -1628,6 +1654,9 @@
             ALOGE("QueueSignalReleaseImageANDROID failed: %d", result);
             swapchain_result = result;
         }
+        if (img.release_fence >= 0)
+            close(img.release_fence);
+        img.release_fence = fence < 0 ? -1 : dup(fence);
 
         if (swapchain.surface.swapchain_handle ==
             present_info->pSwapchains[sc]) {
@@ -1761,7 +1790,7 @@
                     WorstPresentResult(swapchain_result, VK_SUBOPTIMAL_KHR);
             }
         } else {
-            ReleaseSwapchainImage(device, nullptr, fence, img);
+            ReleaseSwapchainImage(device, nullptr, fence, img, true);
             swapchain_result = VK_ERROR_OUT_OF_DATE_KHR;
         }