Merge "SF: Temporarily expose primary display id"
diff --git a/include/input/Input.h b/include/input/Input.h
index f170f0f..d397313 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -579,9 +579,7 @@
 
     void setCursorPosition(float x, float y);
 
-    uint32_t getDisplayOrientation() const { return mDisplayOrientation; }
-
-    int2 getDisplaySize() const { return {mDisplayWidth, mDisplayHeight}; }
+    ui::Transform getRawTransform() const { return mRawTransform; }
 
     static inline bool isValidCursorPosition(float x, float y) { return !isnan(x) && !isnan(y); }
 
@@ -757,8 +755,8 @@
                     int32_t flags, int32_t edgeFlags, int32_t metaState, int32_t buttonState,
                     MotionClassification classification, const ui::Transform& transform,
                     float xPrecision, float yPrecision, float rawXCursorPosition,
-                    float rawYCursorPosition, uint32_t displayOrientation, int32_t displayWidth,
-                    int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime, size_t pointerCount,
+                    float rawYCursorPosition, const ui::Transform& rawTransform, nsecs_t downTime,
+                    nsecs_t eventTime, size_t pointerCount,
                     const PointerProperties* pointerProperties, const PointerCoords* pointerCoords);
 
     void copyFrom(const MotionEvent* other, bool keepHistory);
@@ -816,9 +814,7 @@
     float mYPrecision;
     float mRawXCursorPosition;
     float mRawYCursorPosition;
-    uint32_t mDisplayOrientation;
-    int32_t mDisplayWidth;
-    int32_t mDisplayHeight;
+    ui::Transform mRawTransform;
     nsecs_t mDownTime;
     Vector<PointerProperties> mPointerProperties;
     std::vector<nsecs_t> mSampleEventTimes;
diff --git a/include/input/InputTransport.h b/include/input/InputTransport.h
index 7632b30..d655b28 100644
--- a/include/input/InputTransport.h
+++ b/include/input/InputTransport.h
@@ -114,7 +114,7 @@
 
         struct Motion {
             int32_t eventId;
-            uint32_t empty1;
+            uint32_t pointerCount;
             nsecs_t eventTime __attribute__((aligned(8)));
             int32_t deviceId;
             int32_t source;
@@ -129,20 +129,22 @@
             uint8_t empty2[3];                   // 3 bytes to fill gap created by classification
             int32_t edgeFlags;
             nsecs_t downTime __attribute__((aligned(8)));
-            float dsdx;
-            float dtdx;
-            float dtdy;
-            float dsdy;
-            float tx;
-            float ty;
+            float dsdx; // Begin window transform
+            float dtdx; //
+            float dtdy; //
+            float dsdy; //
+            float tx;   //
+            float ty;   // End window transform
             float xPrecision;
             float yPrecision;
             float xCursorPosition;
             float yCursorPosition;
-            uint32_t displayOrientation;
-            int32_t displayWidth;
-            int32_t displayHeight;
-            uint32_t pointerCount;
+            float dsdxRaw; // Begin raw transform
+            float dtdxRaw; //
+            float dtdyRaw; //
+            float dsdyRaw; //
+            float txRaw;   //
+            float tyRaw;   // End raw transform
             /**
              * The "pointers" field must be the last field of the struct InputMessage.
              * When we send the struct InputMessage across the socket, we are not
@@ -367,9 +369,8 @@
                                 int32_t metaState, int32_t buttonState,
                                 MotionClassification classification, const ui::Transform& transform,
                                 float xPrecision, float yPrecision, float xCursorPosition,
-                                float yCursorPosition, uint32_t displayOrientation,
-                                int32_t displayWidth, int32_t displayHeight, nsecs_t downTime,
-                                nsecs_t eventTime, uint32_t pointerCount,
+                                float yCursorPosition, const ui::Transform& rawTransform,
+                                nsecs_t downTime, nsecs_t eventTime, uint32_t pointerCount,
                                 const PointerProperties* pointerProperties,
                                 const PointerCoords* pointerCoords);
 
diff --git a/libs/binder/Android.bp b/libs/binder/Android.bp
index 06594d7..a86515a 100644
--- a/libs/binder/Android.bp
+++ b/libs/binder/Android.bp
@@ -250,13 +250,16 @@
     export_header_lib_headers: [
         "libbinder_headers",
     ],
+    export_shared_lib_headers: [
+        "libssl",
+    ],
     export_include_dirs: ["include_tls"],
     static_libs: [
         "libbase",
     ],
     srcs: [
         "RpcTransportTls.cpp",
-        "RpcCertificateUtils.cpp",
+        "RpcTlsUtils.cpp",
     ],
 }
 
diff --git a/libs/binder/FdTrigger.cpp b/libs/binder/FdTrigger.cpp
index ecf13dc..49f83ff 100644
--- a/libs/binder/FdTrigger.cpp
+++ b/libs/binder/FdTrigger.cpp
@@ -53,7 +53,7 @@
             continue;
         }
         if (pfd[1].revents & POLLHUP) {
-            return -ECANCELED;
+            return DEAD_OBJECT;
         }
         return pfd[0].revents & event ? OK : DEAD_OBJECT;
     }
diff --git a/libs/binder/RpcState.cpp b/libs/binder/RpcState.cpp
index 11a083a..dcba837 100644
--- a/libs/binder/RpcState.cpp
+++ b/libs/binder/RpcState.cpp
@@ -323,6 +323,7 @@
         status != OK) {
         LOG_RPC_DETAIL("Failed to read %s (%zu bytes) on RpcTransport %p, error: %s", what, size,
                        connection->rpcTransport.get(), statusToString(status).c_str());
+        (void)session->shutdownAndWait(false);
         return status;
     }
 
@@ -531,8 +532,8 @@
                                 const sp<RpcSession>& session, Parcel* reply) {
     RpcWireHeader command;
     while (true) {
-        if (status_t status =
-                    rpcRec(connection, session, "command header", &command, sizeof(command));
+        if (status_t status = rpcRec(connection, session, "command header (for reply)", &command,
+                                     sizeof(command));
             status != OK)
             return status;
 
@@ -601,7 +602,8 @@
     LOG_RPC_DETAIL("getAndExecuteCommand on RpcTransport %p", connection->rpcTransport.get());
 
     RpcWireHeader command;
-    if (status_t status = rpcRec(connection, session, "command header", &command, sizeof(command));
+    if (status_t status = rpcRec(connection, session, "command header (for server)", &command,
+                                 sizeof(command));
         status != OK)
         return status;
 
diff --git a/libs/binder/RpcCertificateUtils.cpp b/libs/binder/RpcTlsUtils.cpp
similarity index 96%
rename from libs/binder/RpcCertificateUtils.cpp
rename to libs/binder/RpcTlsUtils.cpp
index d91736c..483cc7c 100644
--- a/libs/binder/RpcCertificateUtils.cpp
+++ b/libs/binder/RpcTlsUtils.cpp
@@ -14,10 +14,10 @@
  * limitations under the License.
  */
 
-#define LOG_TAG "RpcCertificateUtils"
+#define LOG_TAG "RpcTlsUtils"
 #include <log/log.h>
 
-#include <binder/RpcCertificateUtils.h>
+#include <binder/RpcTlsUtils.h>
 
 #include "Utils.h"
 
diff --git a/libs/binder/RpcTransportTls.cpp b/libs/binder/RpcTransportTls.cpp
index 23088ad..f8cd71d 100644
--- a/libs/binder/RpcTransportTls.cpp
+++ b/libs/binder/RpcTransportTls.cpp
@@ -22,7 +22,7 @@
 #include <openssl/bn.h>
 #include <openssl/ssl.h>
 
-#include <binder/RpcCertificateUtils.h>
+#include <binder/RpcTlsUtils.h>
 #include <binder/RpcTransportTls.h>
 
 #include "FdTrigger.h"
@@ -44,8 +44,6 @@
 namespace android {
 namespace {
 
-constexpr const int kCertValidDays = 30;
-
 // Implement BIO for socket that ignores SIGPIPE.
 int socketNew(BIO* bio) {
     BIO_set_data(bio, reinterpret_cast<void*>(-1));
@@ -100,49 +98,6 @@
     return ret;
 }
 
-bssl::UniquePtr<EVP_PKEY> makeKeyPairForSelfSignedCert() {
-    bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
-    if (ec_key == nullptr || !EC_KEY_generate_key(ec_key.get())) {
-        ALOGE("Failed to generate key pair.");
-        return nullptr;
-    }
-    bssl::UniquePtr<EVP_PKEY> evp_pkey(EVP_PKEY_new());
-    // Use set1 instead of assign to avoid leaking ec_key when assign fails. set1 increments
-    // the refcount of the ec_key, so it is okay to release it at the end of this function.
-    if (evp_pkey == nullptr || !EVP_PKEY_set1_EC_KEY(evp_pkey.get(), ec_key.get())) {
-        ALOGE("Failed to assign key pair.");
-        return nullptr;
-    }
-    return evp_pkey;
-}
-
-bssl::UniquePtr<X509> makeSelfSignedCert(EVP_PKEY* evp_pkey, const int valid_days) {
-    bssl::UniquePtr<X509> x509(X509_new());
-    bssl::UniquePtr<BIGNUM> serial(BN_new());
-    bssl::UniquePtr<BIGNUM> serialLimit(BN_new());
-    TEST_AND_RETURN(nullptr, BN_lshift(serialLimit.get(), BN_value_one(), 128));
-    TEST_AND_RETURN(nullptr, BN_rand_range(serial.get(), serialLimit.get()));
-    TEST_AND_RETURN(nullptr, BN_to_ASN1_INTEGER(serial.get(), X509_get_serialNumber(x509.get())));
-    TEST_AND_RETURN(nullptr, X509_gmtime_adj(X509_getm_notBefore(x509.get()), 0));
-    TEST_AND_RETURN(nullptr,
-                    X509_gmtime_adj(X509_getm_notAfter(x509.get()), 60 * 60 * 24 * valid_days));
-
-    X509_NAME* subject = X509_get_subject_name(x509.get());
-    TEST_AND_RETURN(nullptr,
-                    X509_NAME_add_entry_by_txt(subject, "O", MBSTRING_ASC,
-                                               reinterpret_cast<const uint8_t*>("Android"), -1, -1,
-                                               0));
-    TEST_AND_RETURN(nullptr,
-                    X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC,
-                                               reinterpret_cast<const uint8_t*>("BinderRPC"), -1,
-                                               -1, 0));
-    TEST_AND_RETURN(nullptr, X509_set_issuer_name(x509.get(), subject));
-
-    TEST_AND_RETURN(nullptr, X509_set_pubkey(x509.get(), evp_pkey));
-    TEST_AND_RETURN(nullptr, X509_sign(x509.get(), evp_pkey, EVP_sha256()));
-    return x509;
-}
-
 [[maybe_unused]] void sslDebugLog(const SSL* ssl, int type, int value) {
     switch (type) {
         case SSL_CB_HANDSHAKE_START:
@@ -241,7 +196,7 @@
     status_t handlePoll(int event, android::base::borrowed_fd fd, FdTrigger* fdTrigger,
                         const char* fnString) {
         status_t ret = fdTrigger->triggerablePoll(fd, event);
-        if (ret != OK && ret != DEAD_OBJECT && ret != -ECANCELED) {
+        if (ret != OK && ret != DEAD_OBJECT) {
             ALOGE("triggerablePoll error while poll()-ing after %s(): %s", fnString,
                   statusToString(ret).c_str());
         }
@@ -348,7 +303,7 @@
 
     // Before doing any I/O, check trigger once. This ensures the trigger is checked at least
     // once. The trigger is also checked via triggerablePoll() after every SSL_write().
-    if (fdTrigger->isTriggered()) return -ECANCELED;
+    if (fdTrigger->isTriggered()) return DEAD_OBJECT;
 
     while (buffer < end) {
         size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max());
@@ -379,7 +334,7 @@
 
     // Before doing any I/O, check trigger once. This ensures the trigger is checked at least
     // once. The trigger is also checked via triggerablePoll() after every SSL_write().
-    if (fdTrigger->isTriggered()) return -ECANCELED;
+    if (fdTrigger->isTriggered()) return DEAD_OBJECT;
 
     while (buffer < end) {
         size_t todo = std::min<size_t>(end - buffer, std::numeric_limits<int>::max());
@@ -437,7 +392,7 @@
     template <typename Impl,
               typename = std::enable_if_t<std::is_base_of_v<RpcTransportCtxTls, Impl>>>
     static std::unique_ptr<RpcTransportCtxTls> create(
-            std::shared_ptr<RpcCertificateVerifier> verifier);
+            std::shared_ptr<RpcCertificateVerifier> verifier, RpcAuth* auth);
     std::unique_ptr<RpcTransport> newTransport(android::base::unique_fd fd,
                                                FdTrigger* fdTrigger) const override;
     std::vector<uint8_t> getCertificate(RpcCertificateFormat) const override;
@@ -460,17 +415,13 @@
     LOG_ALWAYS_FATAL_IF(outAlert == nullptr);
     const char* logPrefix = SSL_is_server(ssl) ? "Server" : "Client";
 
-    bssl::UniquePtr<X509> peerCert(SSL_get_peer_certificate(ssl)); // Does not set error queue
-    LOG_ALWAYS_FATAL_IF(peerCert == nullptr,
-                        "%s: libssl should not ask to verify non-existing cert", logPrefix);
-
     auto ctx = SSL_get_SSL_CTX(ssl); // Does not set error queue
     LOG_ALWAYS_FATAL_IF(ctx == nullptr);
     // void* -> RpcTransportCtxTls*
     auto rpcTransportCtxTls = reinterpret_cast<RpcTransportCtxTls*>(SSL_CTX_get_app_data(ctx));
     LOG_ALWAYS_FATAL_IF(rpcTransportCtxTls == nullptr);
 
-    status_t verifyStatus = rpcTransportCtxTls->mCertVerifier->verify(peerCert.get(), outAlert);
+    status_t verifyStatus = rpcTransportCtxTls->mCertVerifier->verify(ssl, outAlert);
     if (verifyStatus == OK) {
         return ssl_verify_ok;
     }
@@ -483,16 +434,15 @@
 // provided as a template argument so that this function can initialize an |Impl| object.
 template <typename Impl, typename>
 std::unique_ptr<RpcTransportCtxTls> RpcTransportCtxTls::create(
-        std::shared_ptr<RpcCertificateVerifier> verifier) {
+        std::shared_ptr<RpcCertificateVerifier> verifier, RpcAuth* auth) {
     bssl::UniquePtr<SSL_CTX> ctx(SSL_CTX_new(TLS_method()));
     TEST_AND_RETURN(nullptr, ctx != nullptr);
 
-    auto evp_pkey = makeKeyPairForSelfSignedCert();
-    TEST_AND_RETURN(nullptr, evp_pkey != nullptr);
-    auto cert = makeSelfSignedCert(evp_pkey.get(), kCertValidDays);
-    TEST_AND_RETURN(nullptr, cert != nullptr);
-    TEST_AND_RETURN(nullptr, SSL_CTX_use_PrivateKey(ctx.get(), evp_pkey.get()));
-    TEST_AND_RETURN(nullptr, SSL_CTX_use_certificate(ctx.get(), cert.get()));
+    if (status_t authStatus = auth->configure(ctx.get()); authStatus != OK) {
+        ALOGE("%s: Failed to configure auth info: %s", __PRETTY_FUNCTION__,
+              statusToString(authStatus).c_str());
+        return nullptr;
+    };
 
     // Enable two-way authentication by setting SSL_VERIFY_FAIL_IF_NO_PEER_CERT on server.
     // Client ignores SSL_VERIFY_FAIL_IF_NO_PEER_CERT flag.
@@ -542,11 +492,13 @@
 } // namespace
 
 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newServerCtx() const {
-    return android::RpcTransportCtxTls::create<RpcTransportCtxTlsServer>(mCertVerifier);
+    return android::RpcTransportCtxTls::create<RpcTransportCtxTlsServer>(mCertVerifier,
+                                                                         mAuth.get());
 }
 
 std::unique_ptr<RpcTransportCtx> RpcTransportCtxFactoryTls::newClientCtx() const {
-    return android::RpcTransportCtxTls::create<RpcTransportCtxTlsClient>(mCertVerifier);
+    return android::RpcTransportCtxTls::create<RpcTransportCtxTlsClient>(mCertVerifier,
+                                                                         mAuth.get());
 }
 
 const char* RpcTransportCtxFactoryTls::toCString() const {
@@ -554,13 +506,17 @@
 }
 
 std::unique_ptr<RpcTransportCtxFactory> RpcTransportCtxFactoryTls::make(
-        std::shared_ptr<RpcCertificateVerifier> verifier) {
+        std::shared_ptr<RpcCertificateVerifier> verifier, std::unique_ptr<RpcAuth> auth) {
     if (verifier == nullptr) {
         ALOGE("%s: Must provide a certificate verifier", __PRETTY_FUNCTION__);
         return nullptr;
     }
+    if (auth == nullptr) {
+        ALOGE("%s: Must provide an auth provider", __PRETTY_FUNCTION__);
+        return nullptr;
+    }
     return std::unique_ptr<RpcTransportCtxFactoryTls>(
-            new RpcTransportCtxFactoryTls(std::move(verifier)));
+            new RpcTransportCtxFactoryTls(std::move(verifier), std::move(auth)));
 }
 
 } // namespace android
diff --git a/libs/binder/include_tls/binder/RpcAuth.h b/libs/binder/include_tls/binder/RpcAuth.h
new file mode 100644
index 0000000..4c2f296
--- /dev/null
+++ b/libs/binder/include_tls/binder/RpcAuth.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <openssl/ssl.h>
+#include <utils/Errors.h>
+
+namespace android {
+
+// An interface with a function that configures the SSL_CTX object with authentication information,
+// including certificates and private keys.
+class RpcAuth {
+public:
+    virtual ~RpcAuth() = default;
+
+    // The keys and certificates to provide is up to the implementation. Multiple calls to
+    // |configure()| may configure |ctx| with the same keys / certificates, or generate a
+    // different key / certificate every time |configure()| is called.
+    //
+    // It is guaranteed that, when a context object (RpcTransportCtx) is created,
+    // libbinder_tls calls |configure()| on server RpcAuth exactly once.
+    //
+    // The implementation may use the following function to set the private
+    // keys and certificates:
+    // - SSL_CTX_use_PrivateKey
+    // - SSL_CTX_use_certificate
+    // - SSL_CTX_set*_chain
+    // - SSL_CTX_add0_chain_cert
+    virtual status_t configure(SSL_CTX* ctx) = 0;
+};
+
+} // namespace android
diff --git a/libs/binder/include/binder/RpcCertificateVerifier.h b/libs/binder/include_tls/binder/RpcCertificateVerifier.h
similarity index 64%
rename from libs/binder/include/binder/RpcCertificateVerifier.h
rename to libs/binder/include_tls/binder/RpcCertificateVerifier.h
index 97af31c..800e375 100644
--- a/libs/binder/include/binder/RpcCertificateVerifier.h
+++ b/libs/binder/include_tls/binder/RpcCertificateVerifier.h
@@ -26,7 +26,18 @@
 class RpcCertificateVerifier {
 public:
     virtual ~RpcCertificateVerifier() = default;
-    virtual status_t verify(const X509* peerCert, uint8_t* outAlert) = 0;
+
+    // The implementation may use the following function to get
+    // the peer certificate and chain:
+    // - SSL_get_peer_certificate
+    // - SSL_get_peer_cert_chain
+    // - SSL_get_peer_full_cert_chain
+    //
+    // The implementation should return OK on success or error codes on error. For example:
+    // - PERMISSION_DENIED for rejected certificates
+    // - NO_INIT for not presenting a certificate when requested
+    // - UNKNOWN_ERROR for other errors
+    virtual status_t verify(const SSL* ssl, uint8_t* outAlert) = 0;
 };
 
 } // namespace android
diff --git a/libs/binder/include_tls/binder/RpcCertificateUtils.h b/libs/binder/include_tls/binder/RpcTlsUtils.h
similarity index 100%
rename from libs/binder/include_tls/binder/RpcCertificateUtils.h
rename to libs/binder/include_tls/binder/RpcTlsUtils.h
diff --git a/libs/binder/include_tls/binder/RpcTransportTls.h b/libs/binder/include_tls/binder/RpcTransportTls.h
index f26a3e9..8a11125 100644
--- a/libs/binder/include_tls/binder/RpcTransportTls.h
+++ b/libs/binder/include_tls/binder/RpcTransportTls.h
@@ -18,6 +18,7 @@
 
 #pragma once
 
+#include <binder/RpcAuth.h>
 #include <binder/RpcCertificateVerifier.h>
 #include <binder/RpcTransport.h>
 
@@ -26,17 +27,20 @@
 // RpcTransportCtxFactory with TLS enabled with self-signed certificate.
 class RpcTransportCtxFactoryTls : public RpcTransportCtxFactory {
 public:
-    static std::unique_ptr<RpcTransportCtxFactory> make(std::shared_ptr<RpcCertificateVerifier>);
+    static std::unique_ptr<RpcTransportCtxFactory> make(std::shared_ptr<RpcCertificateVerifier>,
+                                                        std::unique_ptr<RpcAuth>);
 
     std::unique_ptr<RpcTransportCtx> newServerCtx() const override;
     std::unique_ptr<RpcTransportCtx> newClientCtx() const override;
     const char* toCString() const override;
 
 private:
-    RpcTransportCtxFactoryTls(std::shared_ptr<RpcCertificateVerifier> verifier)
-          : mCertVerifier(std::move(verifier)){};
+    RpcTransportCtxFactoryTls(std::shared_ptr<RpcCertificateVerifier> verifier,
+                              std::unique_ptr<RpcAuth> auth)
+          : mCertVerifier(std::move(verifier)), mAuth(std::move(auth)){};
 
     std::shared_ptr<RpcCertificateVerifier> mCertVerifier;
+    std::unique_ptr<RpcAuth> mAuth;
 };
 
 } // namespace android
diff --git a/libs/binder/rust/src/parcel/file_descriptor.rs b/libs/binder/rust/src/parcel/file_descriptor.rs
index 179b7c8..f71a686 100644
--- a/libs/binder/rust/src/parcel/file_descriptor.rs
+++ b/libs/binder/rust/src/parcel/file_descriptor.rs
@@ -23,7 +23,7 @@
 use crate::sys;
 
 use std::fs::File;
-use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
+use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd};
 
 /// Rust version of the Java class android.os.ParcelFileDescriptor
 #[derive(Debug)]
@@ -54,6 +54,12 @@
     }
 }
 
+impl IntoRawFd for ParcelFileDescriptor {
+    fn into_raw_fd(self) -> RawFd {
+        self.0.into_raw_fd()
+    }
+}
+
 impl Serialize for ParcelFileDescriptor {
     fn serialize(&self, parcel: &mut Parcel) -> Result<()> {
         let fd = self.0.as_raw_fd();
diff --git a/libs/binder/tests/Android.bp b/libs/binder/tests/Android.bp
index 1968058..6f3c6e2 100644
--- a/libs/binder/tests/Android.bp
+++ b/libs/binder/tests/Android.bp
@@ -153,6 +153,7 @@
 
     srcs: [
         "binderRpcTest.cpp",
+        "RpcAuthTesting.cpp",
         "RpcCertificateVerifierSimple.cpp",
     ],
     shared_libs: [
diff --git a/libs/binder/tests/RpcAuthTesting.cpp b/libs/binder/tests/RpcAuthTesting.cpp
new file mode 100644
index 0000000..76f7bce
--- /dev/null
+++ b/libs/binder/tests/RpcAuthTesting.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 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 "RpcAuthTesting.h"
+#include "../Utils.h" // for TEST_AND_RETURN
+
+namespace android {
+
+bssl::UniquePtr<EVP_PKEY> makeKeyPairForSelfSignedCert() {
+    bssl::UniquePtr<EC_KEY> ec_key(EC_KEY_new_by_curve_name(NID_X9_62_prime256v1));
+    if (ec_key == nullptr || !EC_KEY_generate_key(ec_key.get())) {
+        ALOGE("Failed to generate key pair.");
+        return nullptr;
+    }
+    bssl::UniquePtr<EVP_PKEY> pkey(EVP_PKEY_new());
+    // Use set1 instead of assign to avoid leaking ec_key when assign fails. set1 increments
+    // the refcount of the ec_key, so it is okay to release it at the end of this function.
+    if (pkey == nullptr || !EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get())) {
+        ALOGE("Failed to assign key pair.");
+        return nullptr;
+    }
+    return pkey;
+}
+
+bssl::UniquePtr<X509> makeSelfSignedCert(EVP_PKEY* pkey, const uint32_t validSeconds) {
+    bssl::UniquePtr<X509> x509(X509_new());
+    bssl::UniquePtr<BIGNUM> serial(BN_new());
+    bssl::UniquePtr<BIGNUM> serialLimit(BN_new());
+    TEST_AND_RETURN(nullptr, BN_lshift(serialLimit.get(), BN_value_one(), 128));
+    TEST_AND_RETURN(nullptr, BN_rand_range(serial.get(), serialLimit.get()));
+    TEST_AND_RETURN(nullptr, BN_to_ASN1_INTEGER(serial.get(), X509_get_serialNumber(x509.get())));
+    TEST_AND_RETURN(nullptr, X509_gmtime_adj(X509_getm_notBefore(x509.get()), 0));
+    TEST_AND_RETURN(nullptr, X509_gmtime_adj(X509_getm_notAfter(x509.get()), validSeconds));
+
+    X509_NAME* subject = X509_get_subject_name(x509.get());
+    TEST_AND_RETURN(nullptr,
+                    X509_NAME_add_entry_by_txt(subject, "O", MBSTRING_ASC,
+                                               reinterpret_cast<const uint8_t*>("Android"), -1, -1,
+                                               0));
+    TEST_AND_RETURN(nullptr,
+                    X509_NAME_add_entry_by_txt(subject, "CN", MBSTRING_ASC,
+                                               reinterpret_cast<const uint8_t*>("BinderRPC"), -1,
+                                               -1, 0));
+    TEST_AND_RETURN(nullptr, X509_set_issuer_name(x509.get(), subject));
+
+    TEST_AND_RETURN(nullptr, X509_set_pubkey(x509.get(), pkey));
+    TEST_AND_RETURN(nullptr, X509_sign(x509.get(), pkey, EVP_sha256()));
+    return x509;
+}
+
+status_t RpcAuthSelfSigned::configure(SSL_CTX* ctx) {
+    auto pkey = makeKeyPairForSelfSignedCert();
+    TEST_AND_RETURN(UNKNOWN_ERROR, pkey != nullptr);
+    auto cert = makeSelfSignedCert(pkey.get(), mValidSeconds);
+    TEST_AND_RETURN(UNKNOWN_ERROR, cert != nullptr);
+    TEST_AND_RETURN(INVALID_OPERATION, SSL_CTX_use_PrivateKey(ctx, pkey.get()));
+    TEST_AND_RETURN(INVALID_OPERATION, SSL_CTX_use_certificate(ctx, cert.get()));
+    return OK;
+}
+
+} // namespace android
diff --git a/libs/binder/tests/RpcAuthTesting.h b/libs/binder/tests/RpcAuthTesting.h
new file mode 100644
index 0000000..fdc731d
--- /dev/null
+++ b/libs/binder/tests/RpcAuthTesting.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <binder/RpcAuth.h>
+
+namespace android {
+
+constexpr const uint32_t kCertValidSeconds = 30 * (60 * 60 * 24); // 30 days
+bssl::UniquePtr<EVP_PKEY> makeKeyPairForSelfSignedCert();
+bssl::UniquePtr<X509> makeSelfSignedCert(EVP_PKEY* pKey, uint32_t validSeconds);
+
+// An implementation of RpcAuth that generates a key pair and a self-signed
+// certificate every time configure() is called.
+class RpcAuthSelfSigned : public RpcAuth {
+public:
+    RpcAuthSelfSigned(uint32_t validSeconds = kCertValidSeconds) : mValidSeconds(validSeconds) {}
+    status_t configure(SSL_CTX* ctx) override;
+
+private:
+    const uint32_t mValidSeconds;
+};
+
+} // namespace android
diff --git a/libs/binder/tests/RpcCertificateVerifierSimple.cpp b/libs/binder/tests/RpcCertificateVerifierSimple.cpp
index 4694d1b..1f74adc 100644
--- a/libs/binder/tests/RpcCertificateVerifierSimple.cpp
+++ b/libs/binder/tests/RpcCertificateVerifierSimple.cpp
@@ -16,16 +16,21 @@
 #define LOG_TAG "RpcCertificateVerifierSimple"
 #include <log/log.h>
 
-#include <binder/RpcCertificateUtils.h>
+#include <binder/RpcTlsUtils.h>
 
 #include "RpcCertificateVerifierSimple.h"
 
 namespace android {
 
-status_t RpcCertificateVerifierSimple::verify(const X509* peerCert, uint8_t* outAlert) {
+status_t RpcCertificateVerifierSimple::verify(const SSL* ssl, uint8_t* outAlert) {
+    const char* logPrefix = SSL_is_server(ssl) ? "Server" : "Client";
+    bssl::UniquePtr<X509> peerCert(SSL_get_peer_certificate(ssl)); // Does not set error queue
+    LOG_ALWAYS_FATAL_IF(peerCert == nullptr,
+                        "%s: libssl should not ask to verify non-existing cert", logPrefix);
+
     std::lock_guard<std::mutex> lock(mMutex);
     for (const auto& trustedCert : mTrustedPeerCertificates) {
-        if (0 == X509_cmp(trustedCert.get(), peerCert)) {
+        if (0 == X509_cmp(trustedCert.get(), peerCert.get())) {
             return OK;
         }
     }
diff --git a/libs/binder/tests/RpcCertificateVerifierSimple.h b/libs/binder/tests/RpcCertificateVerifierSimple.h
index 1f2e531..bdb2426 100644
--- a/libs/binder/tests/RpcCertificateVerifierSimple.h
+++ b/libs/binder/tests/RpcCertificateVerifierSimple.h
@@ -35,7 +35,7 @@
 // certificate being added.
 class RpcCertificateVerifierSimple : public RpcCertificateVerifier {
 public:
-    status_t verify(const X509*, uint8_t*) override;
+    status_t verify(const SSL*, uint8_t*) override;
 
     // Add a trusted peer certificate. Peers presenting this certificate are accepted.
     //
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 6bcf102..2fd1a2a 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -48,8 +48,9 @@
 
 #include "../FdTrigger.h"
 #include "../RpcSocketAddress.h" // for testing preconnected clients
-#include "../RpcState.h"   // for debugging
-#include "../vm_sockets.h" // for VMADDR_*
+#include "../RpcState.h"         // for debugging
+#include "../vm_sockets.h"       // for VMADDR_*
+#include "RpcAuthTesting.h"
 #include "RpcCertificateVerifierSimple.h"
 
 using namespace std::chrono_literals;
@@ -71,7 +72,8 @@
 }
 
 static inline std::unique_ptr<RpcTransportCtxFactory> newFactory(
-        RpcSecurity rpcSecurity, std::shared_ptr<RpcCertificateVerifier> verifier = nullptr) {
+        RpcSecurity rpcSecurity, std::shared_ptr<RpcCertificateVerifier> verifier = nullptr,
+        std::unique_ptr<RpcAuth> auth = nullptr) {
     switch (rpcSecurity) {
         case RpcSecurity::RAW:
             return RpcTransportCtxFactoryRaw::make();
@@ -79,7 +81,10 @@
             if (verifier == nullptr) {
                 verifier = std::make_shared<RpcCertificateVerifierSimple>();
             }
-            return RpcTransportCtxFactoryTls::make(std::move(verifier));
+            if (auth == nullptr) {
+                auth = std::make_unique<RpcAuthSelfSigned>();
+            }
+            return RpcTransportCtxFactoryTls::make(std::move(verifier), std::move(auth));
         }
         default:
             LOG_ALWAYS_FATAL("Unknown RpcSecurity %d", rpcSecurity);
@@ -1036,6 +1041,14 @@
     for (auto& t : threads) t.join();
 }
 
+static void saturateThreadPool(size_t threadCount, const sp<IBinderRpcTest>& iface) {
+    std::vector<std::thread> threads;
+    for (size_t i = 0; i < threadCount; i++) {
+        threads.push_back(std::thread([&] { EXPECT_OK(iface->sleepMs(500)); }));
+    }
+    for (auto& t : threads) t.join();
+}
+
 TEST_P(BinderRpc, OnewayStressTest) {
     constexpr size_t kNumClientThreads = 10;
     constexpr size_t kNumServerThreads = 10;
@@ -1049,13 +1062,12 @@
             for (size_t j = 0; j < kNumCalls; j++) {
                 EXPECT_OK(proc.rootIface->sendString("a"));
             }
-
-            // check threads are not stuck
-            EXPECT_OK(proc.rootIface->sleepMs(250));
         }));
     }
 
     for (auto& t : threads) t.join();
+
+    saturateThreadPool(kNumServerThreads, proc.rootIface);
 }
 
 TEST_P(BinderRpc, OnewayCallDoesNotWait) {
@@ -1082,26 +1094,23 @@
 
     EXPECT_OK(proc.rootIface->lock());
 
-    for (size_t i = 0; i < kNumSleeps; i++) {
-        // these should be processed serially
+    size_t epochMsBefore = epochMillis();
+
+    // all these *Async commands should be queued on the server sequentially,
+    // even though there are multiple threads.
+    for (size_t i = 0; i + 1 < kNumSleeps; i++) {
         proc.rootIface->sleepMsAsync(kSleepMs);
     }
-    // should also be processesed serially
     EXPECT_OK(proc.rootIface->unlockInMsAsync(kSleepMs));
 
-    size_t epochMsBefore = epochMillis();
+    // this can only return once the final async call has unlocked
     EXPECT_OK(proc.rootIface->lockUnlock());
+
     size_t epochMsAfter = epochMillis();
 
     EXPECT_GT(epochMsAfter, epochMsBefore + kSleepMs * kNumSleeps);
 
-    // pending oneway transactions hold ref, make sure we read data on all
-    // sockets
-    std::vector<std::thread> threads;
-    for (size_t i = 0; i < 1 + kNumExtraServerThreads; i++) {
-        threads.push_back(std::thread([&] { EXPECT_OK(proc.rootIface->sleepMs(250)); }));
-    }
-    for (auto& t : threads) t.join();
+    saturateThreadPool(1 + kNumExtraServerThreads, proc.rootIface);
 }
 
 TEST_P(BinderRpc, OnewayCallExhaustion) {
@@ -1794,9 +1803,9 @@
         }
 
         status = serverTransport->interruptableWriteFully(fdTrigger, msg2.data(), msg2.size());
-        if (status != -ECANCELED)
+        if (status != DEAD_OBJECT)
             return AssertionFailure() << "When FdTrigger is shut down, interruptableWriteFully "
-                                         "should return -ECANCELLED, but it is "
+                                         "should return DEAD_OBJECT, but it is "
                                       << statusToString(status);
         return AssertionSuccess();
     };
@@ -1830,7 +1839,7 @@
     }
     writeCv.notify_all();
     // After this line, server thread unblocks and attempts to write the second message, but
-    // shutdown is triggered, so write should failed with -ECANCELLED. See |serverPostConnect|.
+    // shutdown is triggered, so write should failed with DEAD_OBJECT. See |serverPostConnect|.
     // On the client side, second read fails with DEAD_OBJECT
     ASSERT_FALSE(client.readMessage(msg2));
 }
diff --git a/libs/binder/tests/rpc_fuzzer/Android.bp b/libs/binder/tests/rpc_fuzzer/Android.bp
index 9323bd5..be55eba 100644
--- a/libs/binder/tests/rpc_fuzzer/Android.bp
+++ b/libs/binder/tests/rpc_fuzzer/Android.bp
@@ -14,6 +14,7 @@
     fuzz_config: {
         cc: ["smoreland@google.com"],
     },
+    dictionary: "binder_rpc_fuzzer.dict",
 
     srcs: [
         "main.cpp",
diff --git a/libs/binder/tests/rpc_fuzzer/binder_rpc_fuzzer.dict b/libs/binder/tests/rpc_fuzzer/binder_rpc_fuzzer.dict
new file mode 100644
index 0000000..b110a02
--- /dev/null
+++ b/libs/binder/tests/rpc_fuzzer/binder_rpc_fuzzer.dict
@@ -0,0 +1,2 @@
+# connection okay header
+"cci"
diff --git a/libs/binder/tests/rpc_fuzzer/main.cpp b/libs/binder/tests/rpc_fuzzer/main.cpp
index 230f5c7..c848798 100644
--- a/libs/binder/tests/rpc_fuzzer/main.cpp
+++ b/libs/binder/tests/rpc_fuzzer/main.cpp
@@ -87,8 +87,7 @@
             size_t idx = provider.ConsumeIntegralInRange<size_t>(0, connections.size() - 1);
 
             if (provider.ConsumeBool()) {
-                std::vector<uint8_t> writeData = provider.ConsumeBytes<uint8_t>(
-                        provider.ConsumeIntegralInRange<size_t>(0, provider.remaining_bytes()));
+                std::string writeData = provider.ConsumeRandomLengthString();
                 ssize_t size = TEMP_FAILURE_RETRY(send(connections.at(idx).get(), writeData.data(),
                                                        writeData.size(), MSG_NOSIGNAL));
                 CHECK(errno == EPIPE || size == writeData.size())
@@ -101,7 +100,7 @@
 
     if (hangupBeforeShutdown) {
         connections.clear();
-        while (!server->listSessions().empty() && server->numUninitializedSessions()) {
+        while (!server->listSessions().empty() || server->numUninitializedSessions()) {
             // wait for all threads to finish processing existing information
             usleep(1);
         }
diff --git a/libs/gui/Android.bp b/libs/gui/Android.bp
index 2d1f5a1..8c359c7 100644
--- a/libs/gui/Android.bp
+++ b/libs/gui/Android.bp
@@ -55,6 +55,7 @@
 filegroup {
     name: "guiconstants_aidl",
     srcs: [
+        "android/gui/DropInputMode.aidl",
         "android/**/TouchOcclusionMode.aidl",
     ],
 }
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 1fd9d13..a419a63 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -69,7 +69,8 @@
         isTrustedOverlay(false),
         bufferCrop(Rect::INVALID_RECT),
         destinationFrame(Rect::INVALID_RECT),
-        releaseBufferListener(nullptr) {
+        releaseBufferListener(nullptr),
+        dropInputMode(gui::DropInputMode::NONE) {
     matrix.dsdx = matrix.dtdy = 1.0f;
     matrix.dsdy = matrix.dtdx = 0.0f;
     hdrMetadata.validTypes = 0;
@@ -174,6 +175,7 @@
     SAFE_PARCEL(output.writeBool, isTrustedOverlay);
 
     SAFE_PARCEL(output.writeStrongBinder, releaseBufferEndpoint);
+    SAFE_PARCEL(output.writeUint32, static_cast<uint32_t>(dropInputMode));
     return NO_ERROR;
 }
 
@@ -304,6 +306,10 @@
     SAFE_PARCEL(input.readBool, &isTrustedOverlay);
 
     SAFE_PARCEL(input.readNullableStrongBinder, &releaseBufferEndpoint);
+
+    uint32_t mode;
+    SAFE_PARCEL(input.readUint32, &mode);
+    dropInputMode = static_cast<gui::DropInputMode>(mode);
     return NO_ERROR;
 }
 
@@ -558,6 +564,10 @@
     if (other.what & eProducerDisconnect) {
         what |= eProducerDisconnect;
     }
+    if (other.what & eDropInputModeChanged) {
+        what |= eDropInputModeChanged;
+        dropInputMode = other.dropInputMode;
+    }
     if ((other.what & what) != other.what) {
         ALOGE("Unmerged SurfaceComposer Transaction properties. LayerState::merge needs updating? "
               "other.what=0x%" PRIX64 " what=0x%" PRIX64 " unmerged flags=0x%" PRIX64,
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 364820e..bbd3cca 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -1743,6 +1743,21 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setDropInputMode(
+        const sp<SurfaceControl>& sc, gui::DropInputMode mode) {
+    layer_state_t* s = getLayerState(sc);
+    if (!s) {
+        mStatus = BAD_INDEX;
+        return *this;
+    }
+
+    s->what |= layer_state_t::eDropInputModeChanged;
+    s->dropInputMode = mode;
+
+    registerSurfaceControlForCallback(sc);
+    return *this;
+}
+
 // ---------------------------------------------------------------------------
 
 DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
diff --git a/libs/gui/android/gui/DropInputMode.aidl b/libs/gui/android/gui/DropInputMode.aidl
new file mode 100644
index 0000000..2b31744
--- /dev/null
+++ b/libs/gui/android/gui/DropInputMode.aidl
@@ -0,0 +1,45 @@
+/**
+ * Copyright (c) 2021, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.gui;
+
+
+/**
+  * Input event drop modes: Input event drop options for windows and its children.
+  *
+  * @hide
+  */
+@Backing(type="int")
+enum DropInputMode {
+    /**
+      * Default mode, input events are sent to the target as usual.
+      */
+    NONE,
+
+    /**
+      * Window and its children will not receive any input even if it has a valid input channel.
+      * Touches and keys will be dropped. If a window is focused, it will remain focused but will
+      * not receive any keys. If the window has a touchable region and is the target of an input
+      * event, the event will be dropped and will not go to the window behind. ref: b/197296414
+      */
+    ALL,
+
+    /**
+      * Similar to DROP but input events are only dropped if the window is considered to be
+      * obscured. ref: b/197364677
+      */
+    OBSCURED
+}
diff --git a/libs/gui/include/gui/LayerState.h b/libs/gui/include/gui/LayerState.h
index f14127c..b27102b 100644
--- a/libs/gui/include/gui/LayerState.h
+++ b/libs/gui/include/gui/LayerState.h
@@ -26,6 +26,7 @@
 #include <gui/ITransactionCompletedListener.h>
 #include <math/mat4.h>
 
+#include <android/gui/DropInputMode.h>
 #include <android/gui/FocusRequest.h>
 
 #include <gui/ISurfaceComposer.h>
@@ -118,6 +119,7 @@
         eAutoRefreshChanged = 0x1000'00000000,
         eStretchChanged = 0x2000'00000000,
         eTrustedOverlayChanged = 0x4000'00000000,
+        eDropInputModeChanged = 0x8000'00000000,
     };
 
     layer_state_t();
@@ -248,6 +250,9 @@
     // releaseCallbackId and release fence to all listeners so we store which listener the setBuffer
     // was called with.
     sp<IBinder> releaseBufferEndpoint;
+
+    // Force inputflinger to drop all input events for the layer and its children.
+    gui::DropInputMode dropInputMode;
 };
 
 struct ComposerState {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 450e9a0..403ca0a 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -563,6 +563,7 @@
         Transaction& setBufferCrop(const sp<SurfaceControl>& sc, const Rect& bufferCrop);
         Transaction& setDestinationFrame(const sp<SurfaceControl>& sc,
                                          const Rect& destinationFrame);
+        Transaction& setDropInputMode(const sp<SurfaceControl>& sc, gui::DropInputMode mode);
 
         status_t setDisplaySurface(const sp<IBinder>& token,
                 const sp<IGraphicBufferProducer>& bufferProducer);
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 037849e..30e5d5b 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -76,36 +76,13 @@
     return result;
 }
 
-// Rotates the given point to the specified orientation. If the display width and height are
-// provided, the point is rotated in the screen space. Otherwise, the point is rotated about the
-// origin. This helper is used to avoid the extra overhead of creating new Transforms.
-vec2 rotatePoint(uint32_t orientation, float x, float y, int32_t displayWidth = 0,
-                 int32_t displayHeight = 0) {
-    if (orientation == ui::Transform::ROT_0) {
-        return {x, y};
-    }
-
-    vec2 xy(x, y);
-    if (orientation == ui::Transform::ROT_90) {
-        xy.x = displayHeight - y;
-        xy.y = x;
-    } else if (orientation == ui::Transform::ROT_180) {
-        xy.x = displayWidth - x;
-        xy.y = displayHeight - y;
-    } else if (orientation == ui::Transform::ROT_270) {
-        xy.x = y;
-        xy.y = displayWidth - x;
-    }
-    return xy;
-}
-
-vec2 applyTransformWithoutTranslation(const ui::Transform& transform, float x, float y) {
+vec2 transformWithoutTranslation(const ui::Transform& transform, float x, float y) {
     const vec2 transformedXy = transform.transform(x, y);
     const vec2 transformedOrigin = transform.transform(0, 0);
     return transformedXy - transformedOrigin;
 }
 
-bool shouldDisregardWindowTranslation(uint32_t source) {
+bool shouldDisregardTranslation(uint32_t source) {
     // Pointer events are the only type of events that refer to absolute coordinates on the display,
     // so we should apply the entire window transform. For other types of events, we should make
     // sure to not apply the window translation/offset.
@@ -431,8 +408,7 @@
                              int32_t buttonState, MotionClassification classification,
                              const ui::Transform& transform, float xPrecision, float yPrecision,
                              float rawXCursorPosition, float rawYCursorPosition,
-                             uint32_t displayOrientation, int32_t displayWidth,
-                             int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime,
+                             const ui::Transform& rawTransform, nsecs_t downTime, nsecs_t eventTime,
                              size_t pointerCount, const PointerProperties* pointerProperties,
                              const PointerCoords* pointerCoords) {
     InputEvent::initialize(id, deviceId, source, displayId, hmac);
@@ -448,9 +424,7 @@
     mYPrecision = yPrecision;
     mRawXCursorPosition = rawXCursorPosition;
     mRawYCursorPosition = rawYCursorPosition;
-    mDisplayOrientation = displayOrientation;
-    mDisplayWidth = displayWidth;
-    mDisplayHeight = displayHeight;
+    mRawTransform = rawTransform;
     mDownTime = downTime;
     mPointerProperties.clear();
     mPointerProperties.appendArray(pointerProperties, pointerCount);
@@ -474,9 +448,7 @@
     mYPrecision = other->mYPrecision;
     mRawXCursorPosition = other->mRawXCursorPosition;
     mRawYCursorPosition = other->mRawYCursorPosition;
-    mDisplayOrientation = other->mDisplayOrientation;
-    mDisplayWidth = other->mDisplayWidth;
-    mDisplayHeight = other->mDisplayHeight;
+    mRawTransform = other->mRawTransform;
     mDownTime = other->mDownTime;
     mPointerProperties = other->mPointerProperties;
 
@@ -542,20 +514,19 @@
     if (!isPerWindowInputRotationEnabled()) return coords->getAxisValue(axis);
 
     if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) {
-        // For compatibility, convert raw coordinates into "oriented screen space". Once app
-        // developers are educated about getRaw, we can consider removing this.
-        const vec2 xy = shouldDisregardWindowTranslation(mSource)
-                ? rotatePoint(mDisplayOrientation, coords->getX(), coords->getY())
-                : rotatePoint(mDisplayOrientation, coords->getX(), coords->getY(), mDisplayWidth,
-                              mDisplayHeight);
+        // For compatibility, convert raw coordinates into logical display space.
+        const vec2 xy = shouldDisregardTranslation(mSource)
+                ? transformWithoutTranslation(mRawTransform, coords->getX(), coords->getY())
+                : mRawTransform.transform(coords->getX(), coords->getY());
         static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
         return xy[axis];
     }
 
     if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) {
-        // For compatibility, since we convert raw coordinates into "oriented screen space", we
+        // For compatibility, since we report raw coordinates in logical display space, we
         // need to convert the relative axes into the same orientation for consistency.
-        const vec2 relativeXy = rotatePoint(mDisplayOrientation,
+        const vec2 relativeXy =
+                transformWithoutTranslation(mRawTransform,
                                             coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
                                             coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y));
         return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y;
@@ -569,8 +540,8 @@
     const PointerCoords* coords = getHistoricalRawPointerCoords(pointerIndex, historicalIndex);
 
     if (axis == AMOTION_EVENT_AXIS_X || axis == AMOTION_EVENT_AXIS_Y) {
-        const vec2 xy = shouldDisregardWindowTranslation(mSource)
-                ? applyTransformWithoutTranslation(mTransform, coords->getX(), coords->getY())
+        const vec2 xy = shouldDisregardTranslation(mSource)
+                ? transformWithoutTranslation(mTransform, coords->getX(), coords->getY())
                 : mTransform.transform(coords->getXYValue());
         static_assert(AMOTION_EVENT_AXIS_X == 0 && AMOTION_EVENT_AXIS_Y == 1);
         return xy[axis];
@@ -578,11 +549,9 @@
 
     if (axis == AMOTION_EVENT_AXIS_RELATIVE_X || axis == AMOTION_EVENT_AXIS_RELATIVE_Y) {
         const vec2 relativeXy =
-                applyTransformWithoutTranslation(mTransform,
-                                                 coords->getAxisValue(
-                                                         AMOTION_EVENT_AXIS_RELATIVE_X),
-                                                 coords->getAxisValue(
-                                                         AMOTION_EVENT_AXIS_RELATIVE_Y));
+                transformWithoutTranslation(mTransform,
+                                            coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X),
+                                            coords->getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y));
         return axis == AMOTION_EVENT_AXIS_RELATIVE_X ? relativeXy.x : relativeXy.y;
     }
 
@@ -607,6 +576,8 @@
 
 void MotionEvent::scale(float globalScaleFactor) {
     mTransform.set(mTransform.tx() * globalScaleFactor, mTransform.ty() * globalScaleFactor);
+    mRawTransform.set(mRawTransform.tx() * globalScaleFactor,
+                      mRawTransform.ty() * globalScaleFactor);
     mXPrecision *= globalScaleFactor;
     mYPrecision *= globalScaleFactor;
 
@@ -708,9 +679,11 @@
     mYPrecision = parcel->readFloat();
     mRawXCursorPosition = parcel->readFloat();
     mRawYCursorPosition = parcel->readFloat();
-    mDisplayOrientation = parcel->readUint32();
-    mDisplayWidth = parcel->readInt32();
-    mDisplayHeight = parcel->readInt32();
+
+    result = android::readFromParcel(mRawTransform, *parcel);
+    if (result != OK) {
+        return result;
+    }
     mDownTime = parcel->readInt64();
 
     mPointerProperties.clear();
@@ -770,9 +743,11 @@
     parcel->writeFloat(mYPrecision);
     parcel->writeFloat(mRawXCursorPosition);
     parcel->writeFloat(mRawYCursorPosition);
-    parcel->writeUint32(mDisplayOrientation);
-    parcel->writeInt32(mDisplayWidth);
-    parcel->writeInt32(mDisplayHeight);
+
+    result = android::writeToParcel(mRawTransform, *parcel);
+    if (result != OK) {
+        return result;
+    }
     parcel->writeInt64(mDownTime);
 
     for (size_t i = 0; i < pointerCount; i++) {
diff --git a/libs/input/InputTransport.cpp b/libs/input/InputTransport.cpp
index 91ab008..02a5a08 100644
--- a/libs/input/InputTransport.cpp
+++ b/libs/input/InputTransport.cpp
@@ -203,6 +203,8 @@
         case InputMessage::Type::MOTION: {
             // int32_t eventId
             msg->body.motion.eventId = body.motion.eventId;
+            // uint32_t pointerCount
+            msg->body.motion.pointerCount = body.motion.pointerCount;
             // nsecs_t eventTime
             msg->body.motion.eventTime = body.motion.eventTime;
             // int32_t deviceId
@@ -245,14 +247,14 @@
             msg->body.motion.xCursorPosition = body.motion.xCursorPosition;
             // float yCursorPosition
             msg->body.motion.yCursorPosition = body.motion.yCursorPosition;
-            // uint32_t displayOrientation
-            msg->body.motion.displayOrientation = body.motion.displayOrientation;
-            // int32_t displayWidth
-            msg->body.motion.displayWidth = body.motion.displayWidth;
-            // int32_t displayHeight
-            msg->body.motion.displayHeight = body.motion.displayHeight;
-            // uint32_t pointerCount
-            msg->body.motion.pointerCount = body.motion.pointerCount;
+
+            msg->body.motion.dsdxRaw = body.motion.dsdxRaw;
+            msg->body.motion.dtdxRaw = body.motion.dtdxRaw;
+            msg->body.motion.dtdyRaw = body.motion.dtdyRaw;
+            msg->body.motion.dsdyRaw = body.motion.dsdyRaw;
+            msg->body.motion.txRaw = body.motion.txRaw;
+            msg->body.motion.tyRaw = body.motion.tyRaw;
+
             //struct Pointer pointers[MAX_POINTERS]
             for (size_t i = 0; i < body.motion.pointerCount; i++) {
                 // PointerProperties properties
@@ -542,8 +544,8 @@
         std::array<uint8_t, 32> hmac, int32_t action, int32_t actionButton, int32_t flags,
         int32_t edgeFlags, int32_t metaState, int32_t buttonState,
         MotionClassification classification, const ui::Transform& transform, float xPrecision,
-        float yPrecision, float xCursorPosition, float yCursorPosition, uint32_t displayOrientation,
-        int32_t displayWidth, int32_t displayHeight, nsecs_t downTime, nsecs_t eventTime,
+        float yPrecision, float xCursorPosition, float yCursorPosition,
+        const ui::Transform& rawTransform, nsecs_t downTime, nsecs_t eventTime,
         uint32_t pointerCount, const PointerProperties* pointerProperties,
         const PointerCoords* pointerCoords) {
     if (ATRACE_ENABLED()) {
@@ -603,9 +605,12 @@
     msg.body.motion.yPrecision = yPrecision;
     msg.body.motion.xCursorPosition = xCursorPosition;
     msg.body.motion.yCursorPosition = yCursorPosition;
-    msg.body.motion.displayOrientation = displayOrientation;
-    msg.body.motion.displayWidth = displayWidth;
-    msg.body.motion.displayHeight = displayHeight;
+    msg.body.motion.dsdxRaw = rawTransform.dsdx();
+    msg.body.motion.dtdxRaw = rawTransform.dtdx();
+    msg.body.motion.dtdyRaw = rawTransform.dtdy();
+    msg.body.motion.dsdyRaw = rawTransform.dsdy();
+    msg.body.motion.txRaw = rawTransform.tx();
+    msg.body.motion.tyRaw = rawTransform.ty();
     msg.body.motion.downTime = downTime;
     msg.body.motion.eventTime = eventTime;
     msg.body.motion.pointerCount = pointerCount;
@@ -1391,6 +1396,10 @@
     ui::Transform transform;
     transform.set({msg->body.motion.dsdx, msg->body.motion.dtdx, msg->body.motion.tx,
                    msg->body.motion.dtdy, msg->body.motion.dsdy, msg->body.motion.ty, 0, 0, 1});
+    ui::Transform displayTransform;
+    displayTransform.set({msg->body.motion.dsdxRaw, msg->body.motion.dtdxRaw,
+                          msg->body.motion.txRaw, msg->body.motion.dtdyRaw,
+                          msg->body.motion.dsdyRaw, msg->body.motion.tyRaw, 0, 0, 1});
     event->initialize(msg->body.motion.eventId, msg->body.motion.deviceId, msg->body.motion.source,
                       msg->body.motion.displayId, msg->body.motion.hmac, msg->body.motion.action,
                       msg->body.motion.actionButton, msg->body.motion.flags,
@@ -1398,9 +1407,8 @@
                       msg->body.motion.buttonState, msg->body.motion.classification, transform,
                       msg->body.motion.xPrecision, msg->body.motion.yPrecision,
                       msg->body.motion.xCursorPosition, msg->body.motion.yCursorPosition,
-                      msg->body.motion.displayOrientation, msg->body.motion.displayWidth,
-                      msg->body.motion.displayHeight, msg->body.motion.downTime,
-                      msg->body.motion.eventTime, pointerCount, pointerProperties, pointerCoords);
+                      displayTransform, msg->body.motion.downTime, msg->body.motion.eventTime,
+                      pointerCount, pointerProperties, pointerCoords);
 }
 
 void InputConsumer::initializeTouchModeEvent(TouchModeEvent* event, const InputMessage* msg) {
diff --git a/libs/input/tests/InputEvent_test.cpp b/libs/input/tests/InputEvent_test.cpp
index b1ef753..7e7dfd5 100644
--- a/libs/input/tests/InputEvent_test.cpp
+++ b/libs/input/tests/InputEvent_test.cpp
@@ -226,11 +226,16 @@
     static constexpr float Y_SCALE = 3.0;
     static constexpr float X_OFFSET = 1;
     static constexpr float Y_OFFSET = 1.1;
+    static constexpr float RAW_X_SCALE = 4.0;
+    static constexpr float RAW_Y_SCALE = -5.0;
+    static constexpr float RAW_X_OFFSET = 12;
+    static constexpr float RAW_Y_OFFSET = -41.1;
 
     static const std::optional<bool> INITIAL_PER_WINDOW_INPUT_ROTATION_FLAG_VALUE;
 
     int32_t mId;
     ui::Transform mTransform;
+    ui::Transform mRawTransform;
 
     void SetUp() override;
     void TearDown() override;
@@ -259,6 +264,7 @@
 void MotionEventTest::initializeEventWithHistory(MotionEvent* event) {
     mId = InputEvent::nextId();
     mTransform.set({X_SCALE, 0, X_OFFSET, 0, Y_SCALE, Y_OFFSET, 0, 0, 1});
+    mRawTransform.set({RAW_X_SCALE, 0, RAW_X_OFFSET, 0, RAW_Y_SCALE, RAW_Y_OFFSET, 0, 0, 1});
 
     PointerProperties pointerProperties[2];
     pointerProperties[0].clear();
@@ -294,9 +300,8 @@
                       AMOTION_EVENT_EDGE_FLAG_TOP, AMETA_ALT_ON, AMOTION_EVENT_BUTTON_PRIMARY,
                       MotionClassification::NONE, mTransform, 2.0f, 2.1f,
                       AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                      ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
-                      ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2, pointerProperties,
-                      pointerCoords);
+                      mRawTransform, ARBITRARY_DOWN_TIME, ARBITRARY_EVENT_TIME, 2,
+                      pointerProperties, pointerCoords);
 
     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_X, 110);
     pointerCoords[0].setAxisValue(AMOTION_EVENT_AXIS_Y, 111);
@@ -373,39 +378,37 @@
     ASSERT_EQ(ARBITRARY_EVENT_TIME + 1, event->getHistoricalEventTime(1));
     ASSERT_EQ(ARBITRARY_EVENT_TIME + 2, event->getEventTime());
 
-    ASSERT_EQ(11, event->getHistoricalRawPointerCoords(0, 0)->
-            getAxisValue(AMOTION_EVENT_AXIS_Y));
-    ASSERT_EQ(21, event->getHistoricalRawPointerCoords(1, 0)->
-            getAxisValue(AMOTION_EVENT_AXIS_Y));
-    ASSERT_EQ(111, event->getHistoricalRawPointerCoords(0, 1)->
-            getAxisValue(AMOTION_EVENT_AXIS_Y));
-    ASSERT_EQ(121, event->getHistoricalRawPointerCoords(1, 1)->
-            getAxisValue(AMOTION_EVENT_AXIS_Y));
-    ASSERT_EQ(211, event->getRawPointerCoords(0)->
-            getAxisValue(AMOTION_EVENT_AXIS_Y));
-    ASSERT_EQ(221, event->getRawPointerCoords(1)->
-            getAxisValue(AMOTION_EVENT_AXIS_Y));
+    ASSERT_EQ(11, event->getHistoricalRawPointerCoords(0, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y));
+    ASSERT_EQ(21, event->getHistoricalRawPointerCoords(1, 0)->getAxisValue(AMOTION_EVENT_AXIS_Y));
+    ASSERT_EQ(111, event->getHistoricalRawPointerCoords(0, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y));
+    ASSERT_EQ(121, event->getHistoricalRawPointerCoords(1, 1)->getAxisValue(AMOTION_EVENT_AXIS_Y));
+    ASSERT_EQ(211, event->getRawPointerCoords(0)->getAxisValue(AMOTION_EVENT_AXIS_Y));
+    ASSERT_EQ(221, event->getRawPointerCoords(1)->getAxisValue(AMOTION_EVENT_AXIS_Y));
 
-    ASSERT_EQ(11, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0));
-    ASSERT_EQ(21, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0));
-    ASSERT_EQ(111, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1));
-    ASSERT_EQ(121, event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1));
-    ASSERT_EQ(211, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0));
-    ASSERT_EQ(221, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1));
+    ASSERT_EQ(RAW_Y_OFFSET + 11 * RAW_Y_SCALE,
+              event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 0));
+    ASSERT_EQ(RAW_Y_OFFSET + 21 * RAW_Y_SCALE,
+              event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 0));
+    ASSERT_EQ(RAW_Y_OFFSET + 111 * RAW_Y_SCALE,
+              event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 0, 1));
+    ASSERT_EQ(RAW_Y_OFFSET + 121 * RAW_Y_SCALE,
+              event->getHistoricalRawAxisValue(AMOTION_EVENT_AXIS_Y, 1, 1));
+    ASSERT_EQ(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 0));
+    ASSERT_EQ(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawAxisValue(AMOTION_EVENT_AXIS_Y, 1));
 
-    ASSERT_EQ(10, event->getHistoricalRawX(0, 0));
-    ASSERT_EQ(20, event->getHistoricalRawX(1, 0));
-    ASSERT_EQ(110, event->getHistoricalRawX(0, 1));
-    ASSERT_EQ(120, event->getHistoricalRawX(1, 1));
-    ASSERT_EQ(210, event->getRawX(0));
-    ASSERT_EQ(220, event->getRawX(1));
+    ASSERT_EQ(RAW_X_OFFSET + 10 * RAW_X_SCALE, event->getHistoricalRawX(0, 0));
+    ASSERT_EQ(RAW_X_OFFSET + 20 * RAW_X_SCALE, event->getHistoricalRawX(1, 0));
+    ASSERT_EQ(RAW_X_OFFSET + 110 * RAW_X_SCALE, event->getHistoricalRawX(0, 1));
+    ASSERT_EQ(RAW_X_OFFSET + 120 * RAW_X_SCALE, event->getHistoricalRawX(1, 1));
+    ASSERT_EQ(RAW_X_OFFSET + 210 * RAW_X_SCALE, event->getRawX(0));
+    ASSERT_EQ(RAW_X_OFFSET + 220 * RAW_X_SCALE, event->getRawX(1));
 
-    ASSERT_EQ(11, event->getHistoricalRawY(0, 0));
-    ASSERT_EQ(21, event->getHistoricalRawY(1, 0));
-    ASSERT_EQ(111, event->getHistoricalRawY(0, 1));
-    ASSERT_EQ(121, event->getHistoricalRawY(1, 1));
-    ASSERT_EQ(211, event->getRawY(0));
-    ASSERT_EQ(221, event->getRawY(1));
+    ASSERT_EQ(RAW_Y_OFFSET + 11 * RAW_Y_SCALE, event->getHistoricalRawY(0, 0));
+    ASSERT_EQ(RAW_Y_OFFSET + 21 * RAW_Y_SCALE, event->getHistoricalRawY(1, 0));
+    ASSERT_EQ(RAW_Y_OFFSET + 111 * RAW_Y_SCALE, event->getHistoricalRawY(0, 1));
+    ASSERT_EQ(RAW_Y_OFFSET + 121 * RAW_Y_SCALE, event->getHistoricalRawY(1, 1));
+    ASSERT_EQ(RAW_Y_OFFSET + 211 * RAW_Y_SCALE, event->getRawY(0));
+    ASSERT_EQ(RAW_Y_OFFSET + 221 * RAW_Y_SCALE, event->getRawY(1));
 
     ASSERT_EQ(X_OFFSET + 10 * X_SCALE, event->getHistoricalX(0, 0));
     ASSERT_EQ(X_OFFSET + 20 * X_SCALE, event->getHistoricalX(1, 0));
@@ -543,8 +546,8 @@
     ASSERT_EQ(X_OFFSET * 2, event.getXOffset());
     ASSERT_EQ(Y_OFFSET * 2, event.getYOffset());
 
-    ASSERT_EQ(210 * 2, event.getRawX(0));
-    ASSERT_EQ(211 * 2, event.getRawY(0));
+    ASSERT_EQ((RAW_X_OFFSET + 210 * RAW_X_SCALE) * 2, event.getRawX(0));
+    ASSERT_EQ((RAW_Y_OFFSET + 211 * RAW_Y_SCALE) * 2, event.getRawY(0));
     ASSERT_EQ((X_OFFSET + 210 * X_SCALE) * 2, event.getX(0));
     ASSERT_EQ((Y_OFFSET + 211 * Y_SCALE) * 2, event.getY(0));
     ASSERT_EQ(212, event.getPressure(0));
@@ -592,10 +595,10 @@
     // The geometrical representation is irrelevant to the test, it's just easy to generate
     // and check rotation.  We set the orientation to the same angle.
     // Coordinate system: down is increasing Y, right is increasing X.
-    const float PI_180 = float(M_PI / 180);
-    const float RADIUS = 10;
-    const float ARC = 36;
-    const float ROTATION = ARC * 2;
+    static constexpr float PI_180 = float(M_PI / 180);
+    static constexpr float RADIUS = 10;
+    static constexpr float ARC = 36;
+    static constexpr float ROTATION = ARC * 2;
 
     const size_t pointerCount = 11;
     PointerProperties pointerProperties[pointerCount];
@@ -616,9 +619,8 @@
                      AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
                      MotionClassification::NONE, identityTransform, 0 /*xPrecision*/,
                      0 /*yPrecision*/, 3 + RADIUS /*xCursorPosition*/, 2 /*yCursorPosition*/,
-                     ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
-                     0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties,
-                     pointerCoords);
+                     identityTransform, 0 /*downTime*/, 0 /*eventTime*/, pointerCount,
+                     pointerProperties, pointerCoords);
     float originalRawX = 0 + 3;
     float originalRawY = -RADIUS + 2;
 
@@ -661,7 +663,7 @@
 
 MotionEvent createTouchDownEvent(float x, float y, float dx, float dy,
                                  const ui::Transform& transform,
-                                 uint32_t displayOrientation = ui::Transform::ROT_0) {
+                                 const ui::Transform& rawTransform) {
     std::vector<PointerProperties> pointerProperties;
     pointerProperties.push_back(PointerProperties{/* id */ 0, AMOTION_EVENT_TOOL_TYPE_FINGER});
     std::vector<PointerCoords> pointerCoords;
@@ -677,19 +679,18 @@
                      /* actionButton */ 0, /* flags */ 0, /* edgeFlags */ 0, AMETA_NONE,
                      /* buttonState */ 0, MotionClassification::NONE, transform,
                      /* xPrecision */ 0, /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, displayOrientation,
-                     /* displayWidth */ 400,
-                     /* displayHeight */ 800, eventTime, eventTime, pointerCoords.size(),
-                     pointerProperties.data(), pointerCoords.data());
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, rawTransform, eventTime, eventTime,
+                     pointerCoords.size(), pointerProperties.data(), pointerCoords.data());
     return event;
 }
 
 TEST_F(MotionEventTest, ApplyTransform) {
     // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
     ui::Transform identity;
-    ui::Transform xform(ui::Transform::ROT_90, 800, 400);
-    xform.set(xform.tx() + 20, xform.ty() + 40);
-    MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90);
+    ui::Transform transform(ui::Transform::ROT_90, 800, 400);
+    transform.set(transform.tx() + 20, transform.ty() + 40);
+    ui::Transform rawTransform(ui::Transform::ROT_90, 800, 400);
+    MotionEvent event = createTouchDownEvent(60, 100, 42, 96, transform, rawTransform);
     ASSERT_EQ(700, event.getRawX(0));
     ASSERT_EQ(60, event.getRawY(0));
     ASSERT_NE(event.getRawX(0), event.getX(0));
@@ -698,10 +699,10 @@
     ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
     ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
 
-    MotionEvent changedEvent = createTouchDownEvent(60, 100, 42, 96, identity);
-    const std::array<float, 9> rowMajor{xform[0][0], xform[1][0], xform[2][0],
-                                        xform[0][1], xform[1][1], xform[2][1],
-                                        xform[0][2], xform[1][2], xform[2][2]};
+    MotionEvent changedEvent = createTouchDownEvent(60, 100, 42, 96, identity, identity);
+    const std::array<float, 9> rowMajor{transform[0][0], transform[1][0], transform[2][0],
+                                        transform[0][1], transform[1][1], transform[2][1],
+                                        transform[0][2], transform[1][2], transform[2][2]};
     changedEvent.applyTransform(rowMajor);
 
     // transformContent effectively rotates the raw coordinates, so those should now include
@@ -727,9 +728,9 @@
                                                  AINPUT_SOURCE_JOYSTICK};
     for (uint32_t source : NON_POINTER_SOURCES) {
         // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
-        ui::Transform xform(ui::Transform::ROT_90, 800, 400);
-        xform.set(xform.tx() + 20, xform.ty() + 40);
-        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90);
+        ui::Transform transform(ui::Transform::ROT_90, 800, 400);
+        transform.set(transform.tx() + 20, transform.ty() + 40);
+        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, transform, transform);
         event.setSource(source);
 
         // Since this event comes from a non-pointer source, it should include rotation but not
@@ -741,72 +742,34 @@
     }
 }
 
-TEST_F(MotionEventTest, RawCompatTransform) {
-    {
-        // Make sure raw is raw regardless of transform translation.
-        ui::Transform xform;
-        xform.set(20, 40);
-        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform);
-        ASSERT_EQ(60, event.getRawX(0));
-        ASSERT_EQ(100, event.getRawY(0));
-        ASSERT_NE(event.getRawX(0), event.getX(0));
-        ASSERT_NE(event.getRawY(0), event.getY(0));
-        // Relative values should not be modified.
-        ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
-        ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
-    }
+TEST_F(MotionEventTest, AxesAreCorrectlyTransformed) {
+    const ui::Transform identity;
+    ui::Transform transform;
+    transform.set({1.1, -2.2, 3.3, -4.4, 5.5, -6.6, 0, 0, 1});
+    ui::Transform rawTransform;
+    rawTransform.set({-6.6, 5.5, -4.4, 3.3, -2.2, 1.1, 0, 0, 1});
+    auto transformWithoutTranslation = [](const ui::Transform& t, float x, float y) {
+        auto newPoint = t.transform(x, y);
+        auto newOrigin = t.transform(0, 0);
+        return newPoint - newOrigin;
+    };
 
-    // Next check that getRaw contains rotation (for compatibility) but otherwise is still
-    // "Screen-space". The following tests check all 3 rotations.
-    {
-        // Create a rotate-90 transform with an offset (like a window which isn't fullscreen).
-        ui::Transform xform(ui::Transform::ROT_90, 800, 400);
-        xform.set(xform.tx() + 20, xform.ty() + 40);
-        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90);
-        ASSERT_EQ(700, event.getRawX(0));
-        ASSERT_EQ(60, event.getRawY(0));
-        ASSERT_NE(event.getRawX(0), event.getX(0));
-        ASSERT_NE(event.getRawY(0), event.getY(0));
-        // Relative values should be rotated but not translated.
-        ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
-        ASSERT_EQ(42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
-    }
+    const MotionEvent event = createTouchDownEvent(60, 100, 42, 96, transform, rawTransform);
 
-    {
-        // Same as above, but check rotate-180.
-        ui::Transform xform(ui::Transform::ROT_180, 400, 800);
-        xform.set(xform.tx() + 20, xform.ty() + 40);
-        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_180);
-        ASSERT_EQ(340, event.getRawX(0));
-        ASSERT_EQ(700, event.getRawY(0));
-        // Relative values should be rotated but not translated.
-        ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
-        ASSERT_EQ(-96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
-    }
+    // The x and y axes should have the window transform applied.
+    const auto newPoint = transform.transform(60, 100);
+    ASSERT_EQ(newPoint.x, event.getX(0));
+    ASSERT_EQ(newPoint.y, event.getY(0));
 
-    {
-        // Same as above, but check rotate-270.
-        ui::Transform xform(ui::Transform::ROT_270, 800, 400);
-        xform.set(xform.tx() + 20, xform.ty() + 40);
-        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_270);
-        ASSERT_EQ(100, event.getRawX(0));
-        ASSERT_EQ(340, event.getRawY(0));
-        // Relative values should be rotated but not translated.
-        ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
-        ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
-    }
+    // The raw values should have the display transform applied.
+    const auto raw = rawTransform.transform(60, 100);
+    ASSERT_EQ(raw.x, event.getRawX(0));
+    ASSERT_EQ(raw.y, event.getRawY(0));
 
-    {
-        // Finally, check that raw isn't effected by transform
-        ui::Transform xform(ui::Transform::ROT_270, 800, 400);
-        xform.set(xform.tx() + 20, xform.ty() + 40);
-        MotionEvent event = createTouchDownEvent(60, 100, 42, 96, xform, ui::Transform::ROT_90);
-        ASSERT_EQ(700, event.getRawX(0));
-        ASSERT_EQ(60, event.getRawY(0));
-        // Relative values should be rotated but not translated.
-        ASSERT_EQ(96, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
-        ASSERT_EQ(-42, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
-    }
+    // Relative values should have the window transform applied without any translation.
+    const auto rel = transformWithoutTranslation(transform, 42, 96);
+    ASSERT_EQ(rel.x, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_X, 0));
+    ASSERT_EQ(rel.y, event.getAxisValue(AMOTION_EVENT_AXIS_RELATIVE_Y, 0));
 }
 
 TEST_F(MotionEventTest, Initialize_SetsClassification) {
@@ -832,8 +795,7 @@
                          DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
                          AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, classification,
                          identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                         AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
-                         INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/,
+                         AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, 0 /*downTime*/,
                          0 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
         ASSERT_EQ(classification, event.getClassification());
     }
@@ -854,9 +816,9 @@
     event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, DISPLAY_ID,
                      INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0, AMOTION_EVENT_EDGE_FLAG_NONE,
                      AMETA_NONE, 0, MotionClassification::NONE, identityTransform, 0, 0,
-                     280 /*xCursorPosition*/, 540 /*yCursorPosition*/, ui::Transform::ROT_0,
-                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/, 0 /*eventTime*/,
-                     pointerCount, pointerProperties, pointerCoords);
+                     280 /*xCursorPosition*/, 540 /*yCursorPosition*/, identityTransform,
+                     0 /*downTime*/, 0 /*eventTime*/, pointerCount, pointerProperties,
+                     pointerCoords);
     event.offsetLocation(20, 60);
     ASSERT_EQ(280, event.getRawXCursorPosition());
     ASSERT_EQ(540, event.getRawYCursorPosition());
diff --git a/libs/input/tests/InputPublisherAndConsumer_test.cpp b/libs/input/tests/InputPublisherAndConsumer_test.cpp
index 8db5bf1..d09f2ac 100644
--- a/libs/input/tests/InputPublisherAndConsumer_test.cpp
+++ b/libs/input/tests/InputPublisherAndConsumer_test.cpp
@@ -160,13 +160,14 @@
     constexpr float yScale = 3;
     constexpr float xOffset = -10;
     constexpr float yOffset = -20;
+    constexpr float rawXScale = 4;
+    constexpr float rawYScale = -5;
+    constexpr float rawXOffset = -11;
+    constexpr float rawYOffset = 42;
     constexpr float xPrecision = 0.25;
     constexpr float yPrecision = 0.5;
     constexpr float xCursorPosition = 1.3;
     constexpr float yCursorPosition = 50.6;
-    constexpr uint32_t displayOrientation = ui::Transform::ROT_0;
-    constexpr int32_t displayWidth = 1000;
-    constexpr int32_t displayHeight = 2000;
     constexpr nsecs_t downTime = 3;
     constexpr size_t pointerCount = 3;
     constexpr nsecs_t eventTime = 4;
@@ -192,12 +193,14 @@
 
     ui::Transform transform;
     transform.set({xScale, 0, xOffset, 0, yScale, yOffset, 0, 0, 1});
+    ui::Transform rawTransform;
+    rawTransform.set({rawXScale, 0, rawXOffset, 0, rawYScale, rawYOffset, 0, 0, 1});
     status = mPublisher->publishMotionEvent(seq, eventId, deviceId, source, displayId, hmac, action,
                                             actionButton, flags, edgeFlags, metaState, buttonState,
                                             classification, transform, xPrecision, yPrecision,
-                                            xCursorPosition, yCursorPosition, displayOrientation,
-                                            displayWidth, displayHeight, downTime, eventTime,
-                                            pointerCount, pointerProperties, pointerCoords);
+                                            xCursorPosition, yCursorPosition, rawTransform,
+                                            downTime, eventTime, pointerCount, pointerProperties,
+                                            pointerCoords);
     ASSERT_EQ(OK, status)
             << "publisher publishMotionEvent should return OK";
 
@@ -234,9 +237,7 @@
     EXPECT_EQ(yCursorPosition, motionEvent->getRawYCursorPosition());
     EXPECT_EQ(xCursorPosition * xScale + xOffset, motionEvent->getXCursorPosition());
     EXPECT_EQ(yCursorPosition * yScale + yOffset, motionEvent->getYCursorPosition());
-    EXPECT_EQ(displayOrientation, motionEvent->getDisplayOrientation());
-    EXPECT_EQ(displayWidth, motionEvent->getDisplaySize().x);
-    EXPECT_EQ(displayHeight, motionEvent->getDisplaySize().y);
+    EXPECT_EQ(rawTransform, motionEvent->getRawTransform());
     EXPECT_EQ(downTime, motionEvent->getDownTime());
     EXPECT_EQ(eventTime, motionEvent->getEventTime());
     EXPECT_EQ(pointerCount, motionEvent->getPointerCount());
@@ -247,28 +248,18 @@
         EXPECT_EQ(pointerProperties[i].id, motionEvent->getPointerId(i));
         EXPECT_EQ(pointerProperties[i].toolType, motionEvent->getToolType(i));
 
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X),
-                motionEvent->getRawX(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y),
-                motionEvent->getRawY(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_X) * xScale + xOffset,
-                  motionEvent->getX(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_Y) * yScale + yOffset,
-                  motionEvent->getY(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_PRESSURE),
-                motionEvent->getPressure(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_SIZE),
-                motionEvent->getSize(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR),
-                motionEvent->getTouchMajor(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR),
-                motionEvent->getTouchMinor(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR),
-                motionEvent->getToolMajor(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR),
-                motionEvent->getToolMinor(i));
-        EXPECT_EQ(pointerCoords[i].getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION),
-                motionEvent->getOrientation(i));
+        const auto& pc = pointerCoords[i];
+        EXPECT_EQ(pc.getX() * rawXScale + rawXOffset, motionEvent->getRawX(i));
+        EXPECT_EQ(pc.getY() * rawYScale + rawYOffset, motionEvent->getRawY(i));
+        EXPECT_EQ(pc.getX() * xScale + xOffset, motionEvent->getX(i));
+        EXPECT_EQ(pc.getY() * yScale + yOffset, motionEvent->getY(i));
+        EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_PRESSURE), motionEvent->getPressure(i));
+        EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_SIZE), motionEvent->getSize(i));
+        EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MAJOR), motionEvent->getTouchMajor(i));
+        EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOUCH_MINOR), motionEvent->getTouchMinor(i));
+        EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MAJOR), motionEvent->getToolMajor(i));
+        EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_TOOL_MINOR), motionEvent->getToolMinor(i));
+        EXPECT_EQ(pc.getAxisValue(AMOTION_EVENT_AXIS_ORIENTATION), motionEvent->getOrientation(i));
     }
 
     status = mConsumer->sendFinishedSignal(seq, false);
@@ -505,12 +496,12 @@
     }
 
     ui::Transform identityTransform;
-    status = mPublisher->publishMotionEvent(0, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
-                                            0, 0, 0, MotionClassification::NONE, identityTransform,
-                                            0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                            AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                            ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount,
-                                            pointerProperties, pointerCoords);
+    status =
+            mPublisher->publishMotionEvent(0, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
+                                           0, 0, 0, MotionClassification::NONE, identityTransform,
+                                           0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                           AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform,
+                                           0, 0, pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
@@ -522,12 +513,12 @@
     PointerCoords pointerCoords[pointerCount];
 
     ui::Transform identityTransform;
-    status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
-                                            0, 0, 0, MotionClassification::NONE, identityTransform,
-                                            0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                            AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                            ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount,
-                                            pointerProperties, pointerCoords);
+    status =
+            mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
+                                           0, 0, 0, MotionClassification::NONE, identityTransform,
+                                           0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                           AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform,
+                                           0, 0, pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
@@ -544,12 +535,12 @@
     }
 
     ui::Transform identityTransform;
-    status = mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
-                                            0, 0, 0, MotionClassification::NONE, identityTransform,
-                                            0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                            AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                                            ui::Transform::ROT_0, 0, 0, 0, 0, pointerCount,
-                                            pointerProperties, pointerCoords);
+    status =
+            mPublisher->publishMotionEvent(1, InputEvent::nextId(), 0, 0, 0, INVALID_HMAC, 0, 0, 0,
+                                           0, 0, 0, MotionClassification::NONE, identityTransform,
+                                           0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
+                                           AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform,
+                                           0, 0, pointerCount, pointerProperties, pointerCoords);
     ASSERT_EQ(BAD_VALUE, status)
             << "publisher publishMotionEvent should return BAD_VALUE";
 }
diff --git a/libs/input/tests/StructLayout_test.cpp b/libs/input/tests/StructLayout_test.cpp
index 18289a5..2f88704 100644
--- a/libs/input/tests/StructLayout_test.cpp
+++ b/libs/input/tests/StructLayout_test.cpp
@@ -49,7 +49,7 @@
   CHECK_OFFSET(InputMessage::Body::Key, downTime, 88);
 
   CHECK_OFFSET(InputMessage::Body::Motion, eventId, 0);
-  CHECK_OFFSET(InputMessage::Body::Motion, empty1, 4);
+  CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 4);
   CHECK_OFFSET(InputMessage::Body::Motion, eventTime, 8);
   CHECK_OFFSET(InputMessage::Body::Motion, deviceId, 16);
   CHECK_OFFSET(InputMessage::Body::Motion, source, 20);
@@ -74,11 +74,13 @@
   CHECK_OFFSET(InputMessage::Body::Motion, yPrecision, 124);
   CHECK_OFFSET(InputMessage::Body::Motion, xCursorPosition, 128);
   CHECK_OFFSET(InputMessage::Body::Motion, yCursorPosition, 132);
-  CHECK_OFFSET(InputMessage::Body::Motion, displayOrientation, 136);
-  CHECK_OFFSET(InputMessage::Body::Motion, displayWidth, 140);
-  CHECK_OFFSET(InputMessage::Body::Motion, displayHeight, 144);
-  CHECK_OFFSET(InputMessage::Body::Motion, pointerCount, 148);
-  CHECK_OFFSET(InputMessage::Body::Motion, pointers, 152);
+  CHECK_OFFSET(InputMessage::Body::Motion, dsdxRaw, 136);
+  CHECK_OFFSET(InputMessage::Body::Motion, dtdxRaw, 140);
+  CHECK_OFFSET(InputMessage::Body::Motion, dtdyRaw, 144);
+  CHECK_OFFSET(InputMessage::Body::Motion, dsdyRaw, 148);
+  CHECK_OFFSET(InputMessage::Body::Motion, txRaw, 152);
+  CHECK_OFFSET(InputMessage::Body::Motion, tyRaw, 156);
+  CHECK_OFFSET(InputMessage::Body::Motion, pointers, 160);
 
   CHECK_OFFSET(InputMessage::Body::Focus, eventId, 0);
   CHECK_OFFSET(InputMessage::Body::Focus, hasFocus, 4);
diff --git a/libs/input/tests/VelocityTracker_test.cpp b/libs/input/tests/VelocityTracker_test.cpp
index 13e2b02..3039362 100644
--- a/libs/input/tests/VelocityTracker_test.cpp
+++ b/libs/input/tests/VelocityTracker_test.cpp
@@ -184,8 +184,7 @@
                          AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
                          MotionClassification::NONE, identityTransform, 0 /*xPrecision*/,
                          0 /*yPrecision*/, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                         AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
-                         INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 0 /*downTime*/,
+                         AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, 0 /*downTime*/,
                          entry.eventTime.count(), pointerCount, properties, coords);
 
         events.emplace_back(event);
diff --git a/libs/input/tests/VerifiedInputEvent_test.cpp b/libs/input/tests/VerifiedInputEvent_test.cpp
index b29c9a4..f2b59ea 100644
--- a/libs/input/tests/VerifiedInputEvent_test.cpp
+++ b/libs/input/tests/VerifiedInputEvent_test.cpp
@@ -43,12 +43,12 @@
 
     ui::Transform transform;
     transform.set({2, 0, 4, 0, 3, 5, 0, 0, 1});
+    ui::Transform identity;
     event.initialize(InputEvent::nextId(), 0 /*deviceId*/, AINPUT_SOURCE_MOUSE, ADISPLAY_ID_DEFAULT,
                      INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0 /*actionButton*/, flags,
                      AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0 /*buttonState*/,
                      MotionClassification::NONE, transform, 0.1 /*xPrecision*/, 0.2 /*yPrecision*/,
-                     280 /*xCursorPosition*/, 540 /*yCursorPosition*/, ui::Transform::ROT_0,
-                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, 100 /*downTime*/,
+                     280 /*xCursorPosition*/, 540 /*yCursorPosition*/, identity, 100 /*downTime*/,
                      200 /*eventTime*/, pointerCount, pointerProperties, pointerCoords);
     return event;
 }
diff --git a/libs/ui/Android.bp b/libs/ui/Android.bp
index ba5a64f..04ba485 100644
--- a/libs/ui/Android.bp
+++ b/libs/ui/Android.bp
@@ -86,6 +86,7 @@
 
     export_include_dirs: [
         "include",
+        "include_mock",
         "include_private",
         "include_types",
     ],
diff --git a/libs/ui/include/ui/Fence.h b/libs/ui/include/ui/Fence.h
index 6efecd3..7634007 100644
--- a/libs/ui/include/ui/Fence.h
+++ b/libs/ui/include/ui/Fence.h
@@ -26,6 +26,10 @@
 
 namespace android {
 
+namespace mock {
+class MockFence;
+}
+
 class String8;
 
 // ===========================================================================
@@ -109,7 +113,7 @@
     // fence transitioned to the signaled state.  If the fence is not signaled
     // then SIGNAL_TIME_PENDING is returned.  If the fence is invalid or if an
     // error occurs then SIGNAL_TIME_INVALID is returned.
-    nsecs_t getSignalTime() const;
+    virtual nsecs_t getSignalTime() const;
 
     enum class Status {
         Invalid,     // Fence is invalid
@@ -144,7 +148,10 @@
 private:
     // Only allow instantiation using ref counting.
     friend class LightRefBase<Fence>;
-    ~Fence() = default;
+    virtual ~Fence() = default;
+
+    // Allow mocking for unit testing
+    friend class mock::MockFence;
 
     base::unique_fd mFenceFd;
 };
diff --git a/libs/binder/include/binder/RpcCertificateVerifier.h b/libs/ui/include_mock/ui/MockFence.h
similarity index 61%
copy from libs/binder/include/binder/RpcCertificateVerifier.h
copy to libs/ui/include_mock/ui/MockFence.h
index 97af31c..162ec02 100644
--- a/libs/binder/include/binder/RpcCertificateVerifier.h
+++ b/libs/ui/include_mock/ui/MockFence.h
@@ -16,17 +16,17 @@
 
 #pragma once
 
-#include <openssl/ssl.h>
-#include <utils/Errors.h>
+#include <gmock/gmock.h>
+#include <ui/Fence.h>
 
-namespace android {
+namespace android::mock {
 
-// An interface with a function that verifies a peer certificate. It is a wrapper over the custom
-// verify function (see SSL_CTX_set_custom_verify).
-class RpcCertificateVerifier {
+class MockFence : public android::Fence {
 public:
-    virtual ~RpcCertificateVerifier() = default;
-    virtual status_t verify(const X509* peerCert, uint8_t* outAlert) = 0;
+    MockFence() = default;
+    virtual ~MockFence() = default;
+
+    MOCK_METHOD(nsecs_t, getSignalTime, (), (const, override));
 };
 
-} // namespace android
+}; // namespace android::mock
diff --git a/libs/ui/tests/Android.bp b/libs/ui/tests/Android.bp
index 516aad8..a87740a 100644
--- a/libs/ui/tests/Android.bp
+++ b/libs/ui/tests/Android.bp
@@ -115,3 +115,12 @@
     srcs: ["Size_test.cpp"],
     cflags: ["-Wall", "-Werror"],
 }
+
+cc_test {
+    name: "MockFence_test",
+    shared_libs: ["libui"],
+    static_libs: ["libgmock"],
+    srcs: ["MockFence_test.cpp"],
+    cflags: ["-Wall", "-Werror"],
+}
+
diff --git a/libs/ui/tests/MockFence_test.cpp b/libs/ui/tests/MockFence_test.cpp
new file mode 100644
index 0000000..6e520b1
--- /dev/null
+++ b/libs/ui/tests/MockFence_test.cpp
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <ui/MockFence.h>
+
+#include <gtest/gtest.h>
+
+namespace android::ui {
+
+using testing::Return;
+
+class MockFenceTest : public testing::Test {
+public:
+    sp<Fence> getFenceForTesting() const { return mMockFence; }
+
+    const mock::MockFence& getMockFence() const { return *mMockFence; }
+
+private:
+    sp<mock::MockFence> mMockFence = sp<mock::MockFence>::make();
+};
+
+TEST_F(MockFenceTest, getSignalTime) {
+    sp<Fence> fence = getFenceForTesting();
+
+    EXPECT_CALL(getMockFence(), getSignalTime).WillOnce(Return(Fence::SIGNAL_TIME_PENDING));
+    EXPECT_EQ(Fence::SIGNAL_TIME_PENDING, fence->getSignalTime());
+
+    EXPECT_CALL(getMockFence(), getSignalTime).WillOnce(Return(1234));
+    EXPECT_EQ(1234, fence->getSignalTime());
+}
+
+} // namespace android::ui
diff --git a/services/inputflinger/InputManager.h b/services/inputflinger/InputManager.h
index 4c07c22..f053568 100644
--- a/services/inputflinger/InputManager.h
+++ b/services/inputflinger/InputManager.h
@@ -30,7 +30,6 @@
 #include <input/InputTransport.h>
 
 #include <android/os/BnInputFlinger.h>
-#include <android/os/IInputFlinger.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 #include <utils/Timers.h>
diff --git a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
index 6ce0313..68d25f9 100644
--- a/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
+++ b/services/inputflinger/benchmarks/InputDispatcher_benchmarks.cpp
@@ -236,8 +236,8 @@
                      /* edgeFlags */ 0, AMETA_NONE, /* buttonState */ 0, MotionClassification::NONE,
                      identityTransform, /* xPrecision */ 0,
                      /* yPrecision */ 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
-                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, currentTime, currentTime,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, currentTime,
+                     currentTime,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     return event;
 }
diff --git a/services/inputflinger/dispatcher/Entry.cpp b/services/inputflinger/dispatcher/Entry.cpp
index 571c126..bcb0071 100644
--- a/services/inputflinger/dispatcher/Entry.cpp
+++ b/services/inputflinger/dispatcher/Entry.cpp
@@ -309,15 +309,14 @@
 volatile int32_t DispatchEntry::sNextSeqAtomic;
 
 DispatchEntry::DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
-                             ui::Transform transform, float globalScaleFactor,
-                             uint32_t displayOrientation, int2 displaySize)
+                             const ui::Transform& transform, const ui::Transform& rawTransform,
+                             float globalScaleFactor)
       : seq(nextSeq()),
         eventEntry(std::move(eventEntry)),
         targetFlags(targetFlags),
         transform(transform),
+        rawTransform(rawTransform),
         globalScaleFactor(globalScaleFactor),
-        displayOrientation(displayOrientation),
-        displaySize(displaySize),
         deliveryTime(0),
         resolvedAction(0),
         resolvedFlags(0) {}
diff --git a/services/inputflinger/dispatcher/Entry.h b/services/inputflinger/dispatcher/Entry.h
index 5365a78..7a121ce 100644
--- a/services/inputflinger/dispatcher/Entry.h
+++ b/services/inputflinger/dispatcher/Entry.h
@@ -226,9 +226,8 @@
     std::shared_ptr<EventEntry> eventEntry; // the event to dispatch
     int32_t targetFlags;
     ui::Transform transform;
+    ui::Transform rawTransform;
     float globalScaleFactor;
-    uint32_t displayOrientation;
-    int2 displaySize;
     // Both deliveryTime and timeoutTime are only populated when the entry is sent to the app,
     // and will be undefined before that.
     nsecs_t deliveryTime; // time when the event was actually delivered
@@ -241,8 +240,8 @@
     int32_t resolvedFlags;
 
     DispatchEntry(std::shared_ptr<EventEntry> eventEntry, int32_t targetFlags,
-                  ui::Transform transform, float globalScaleFactor, uint32_t displayOrientation,
-                  int2 displaySize);
+                  const ui::Transform& transform, const ui::Transform& rawTransform,
+                  float globalScaleFactor);
 
     inline bool hasForegroundTarget() const { return targetFlags & InputTarget::FLAG_FOREGROUND; }
 
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index da3e237..5f48c1d 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -346,18 +346,15 @@
             // Use identity transform for joystick and position-based (touchpad) events because they
             // don't depend on the window transform.
             return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, identityTransform,
-                                                   1.0f /*globalScaleFactor*/,
-                                                   inputTarget.displayOrientation,
-                                                   inputTarget.displaySize);
+                                                   identityTransform, 1.0f /*globalScaleFactor*/);
         }
     }
 
     if (inputTarget.useDefaultPointerTransform()) {
         const ui::Transform& transform = inputTarget.getDefaultPointerTransform();
         return std::make_unique<DispatchEntry>(eventEntry, inputTargetFlags, transform,
-                                               inputTarget.globalScaleFactor,
-                                               inputTarget.displayOrientation,
-                                               inputTarget.displaySize);
+                                               inputTarget.displayTransform,
+                                               inputTarget.globalScaleFactor);
     }
 
     ALOG_ASSERT(eventEntry->type == EventEntry::Type::MOTION);
@@ -408,24 +405,11 @@
 
     std::unique_ptr<DispatchEntry> dispatchEntry =
             std::make_unique<DispatchEntry>(std::move(combinedMotionEntry), inputTargetFlags,
-                                            firstPointerTransform, inputTarget.globalScaleFactor,
-                                            inputTarget.displayOrientation,
-                                            inputTarget.displaySize);
+                                            firstPointerTransform, inputTarget.displayTransform,
+                                            inputTarget.globalScaleFactor);
     return dispatchEntry;
 }
 
-void addGestureMonitors(const std::vector<Monitor>& monitors,
-                        std::vector<TouchedMonitor>& outTouchedMonitors, float xOffset = 0,
-                        float yOffset = 0) {
-    if (monitors.empty()) {
-        return;
-    }
-    outTouchedMonitors.reserve(monitors.size() + outTouchedMonitors.size());
-    for (const Monitor& monitor : monitors) {
-        outTouchedMonitors.emplace_back(monitor, xOffset, yOffset);
-    }
-}
-
 status_t openInputChannelPair(const std::string& name, std::shared_ptr<InputChannel>& serverChannel,
                               std::unique_ptr<InputChannel>& clientChannel) {
     std::unique_ptr<InputChannel> uniqueServerChannel;
@@ -947,10 +931,9 @@
         }
 
         // Alternatively, maybe there's a gesture monitor that could handle this event
-        std::vector<TouchedMonitor> gestureMonitors = findTouchedGestureMonitorsLocked(displayId);
-        for (TouchedMonitor& gestureMonitor : gestureMonitors) {
+        for (const auto& monitor : getValueByKey(mGestureMonitorsByDisplay, displayId)) {
             sp<Connection> connection =
-                    getConnectionLocked(gestureMonitor.monitor.inputChannel->getConnectionToken());
+                    getConnectionLocked(monitor.inputChannel->getConnectionToken());
             if (connection != nullptr && connection->responsive) {
                 // This monitor could take more input. Drop all events preceding this
                 // event, so that gesture monitor could get a chance to receive the stream
@@ -1077,15 +1060,6 @@
     return nullptr;
 }
 
-std::vector<TouchedMonitor> InputDispatcher::findTouchedGestureMonitorsLocked(
-        int32_t displayId) const {
-    std::vector<TouchedMonitor> touchedMonitors;
-
-    std::vector<Monitor> monitors = getValueByKey(mGestureMonitorsByDisplay, displayId);
-    addGestureMonitors(monitors, touchedMonitors);
-    return touchedMonitors;
-}
-
 void InputDispatcher::dropInboundEventLocked(const EventEntry& entry, DropReason dropReason) {
     const char* reason;
     switch (dropReason) {
@@ -1947,16 +1921,16 @@
  * Given a list of monitors, remove the ones we cannot find a connection for, and the ones
  * that are currently unresponsive.
  */
-std::vector<TouchedMonitor> InputDispatcher::selectResponsiveMonitorsLocked(
-        const std::vector<TouchedMonitor>& monitors) const {
-    std::vector<TouchedMonitor> responsiveMonitors;
+std::vector<Monitor> InputDispatcher::selectResponsiveMonitorsLocked(
+        const std::vector<Monitor>& monitors) const {
+    std::vector<Monitor> responsiveMonitors;
     std::copy_if(monitors.begin(), monitors.end(), std::back_inserter(responsiveMonitors),
-                 [this](const TouchedMonitor& monitor) REQUIRES(mLock) {
-                     sp<Connection> connection = getConnectionLocked(
-                             monitor.monitor.inputChannel->getConnectionToken());
+                 [this](const Monitor& monitor) REQUIRES(mLock) {
+                     sp<Connection> connection =
+                             getConnectionLocked(monitor.inputChannel->getConnectionToken());
                      if (connection == nullptr) {
                          ALOGE("Could not find connection for monitor %s",
-                               monitor.monitor.inputChannel->getName().c_str());
+                               monitor.inputChannel->getName().c_str());
                          return false;
                      }
                      if (!connection->responsive) {
@@ -2057,14 +2031,10 @@
             x = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_X));
             y = int32_t(entry.pointerCoords[pointerIndex].getAxisValue(AMOTION_EVENT_AXIS_Y));
         }
-        bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN;
+        const bool isDown = maskedAction == AMOTION_EVENT_ACTION_DOWN;
         newTouchedWindowHandle = findTouchedWindowAtLocked(displayId, x, y, &tempTouchState,
                                                            isDown /*addOutsideTargets*/);
 
-        std::vector<TouchedMonitor> newGestureMonitors = isDown
-                ? findTouchedGestureMonitorsLocked(displayId)
-                : std::vector<TouchedMonitor>{};
-
         // Figure out whether splitting will be allowed for this window.
         if (newTouchedWindowHandle != nullptr &&
             newTouchedWindowHandle->getInfo()->supportsSplitTouch()) {
@@ -2124,8 +2094,10 @@
             newTouchedWindowHandle = nullptr;
         }
 
-        // Also don't send the new touch event to unresponsive gesture monitors
-        newGestureMonitors = selectResponsiveMonitorsLocked(newGestureMonitors);
+        const std::vector<Monitor> newGestureMonitors = isDown
+                ? selectResponsiveMonitorsLocked(
+                          getValueByKey(mGestureMonitorsByDisplay, displayId))
+                : std::vector<Monitor>{};
 
         if (newTouchedWindowHandle == nullptr && newGestureMonitors.empty()) {
             ALOGI("Dropping event because there is no touchable window or gesture monitor at "
@@ -2345,9 +2317,8 @@
                               touchedWindow.pointerIds, inputTargets);
     }
 
-    for (const TouchedMonitor& touchedMonitor : tempTouchState.gestureMonitors) {
-        addMonitoringTargetLocked(touchedMonitor.monitor, touchedMonitor.xOffset,
-                                  touchedMonitor.yOffset, inputTargets);
+    for (const auto& monitor : tempTouchState.gestureMonitors) {
+        addMonitoringTargetLocked(monitor, displayId, inputTargets);
     }
 
     // Drop the outside or hover touch windows since we will not care about them
@@ -2526,9 +2497,7 @@
         inputTarget.globalScaleFactor = windowInfo->globalScaleFactor;
         const auto& displayInfoIt = mDisplayInfos.find(windowInfo->displayId);
         if (displayInfoIt != mDisplayInfos.end()) {
-            const auto& displayInfo = displayInfoIt->second;
-            inputTarget.displayOrientation = displayInfo.transform.getOrientation();
-            inputTarget.displaySize = int2(displayInfo.logicalWidth, displayInfo.logicalHeight);
+            inputTarget.displayTransform = displayInfoIt->second.transform;
         } else {
             ALOGI_IF(isPerWindowInputRotationEnabled(),
                      "DisplayInfo not found for window on display: %d", windowInfo->displayId);
@@ -2544,27 +2513,44 @@
 }
 
 void InputDispatcher::addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets,
-                                                       int32_t displayId, float xOffset,
-                                                       float yOffset) {
+                                                       int32_t displayId) {
     std::unordered_map<int32_t, std::vector<Monitor>>::const_iterator it =
             mGlobalMonitorsByDisplay.find(displayId);
 
     if (it != mGlobalMonitorsByDisplay.end()) {
         const std::vector<Monitor>& monitors = it->second;
         for (const Monitor& monitor : monitors) {
-            addMonitoringTargetLocked(monitor, xOffset, yOffset, inputTargets);
+            addMonitoringTargetLocked(monitor, displayId, inputTargets);
         }
     }
 }
 
-void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, float xOffset,
-                                                float yOffset,
+void InputDispatcher::addMonitoringTargetLocked(const Monitor& monitor, int32_t displayId,
                                                 std::vector<InputTarget>& inputTargets) {
     InputTarget target;
     target.inputChannel = monitor.inputChannel;
     target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
     ui::Transform t;
-    t.set(xOffset, yOffset);
+    if (const auto& it = mDisplayInfos.find(displayId); it != mDisplayInfos.end()) {
+        // Input monitors always get un-rotated display coordinates. We undo the display
+        // rotation that is present in the display transform so that display rotation is not
+        // applied to these input targets.
+        const auto& displayInfo = it->second;
+        int32_t width = displayInfo.logicalWidth;
+        int32_t height = displayInfo.logicalHeight;
+        const auto orientation = displayInfo.transform.getOrientation();
+        uint32_t inverseOrientation = orientation;
+        if (orientation == ui::Transform::ROT_90) {
+            inverseOrientation = ui::Transform::ROT_270;
+            std::swap(width, height);
+        } else if (orientation == ui::Transform::ROT_270) {
+            inverseOrientation = ui::Transform::ROT_90;
+            std::swap(width, height);
+        }
+        target.displayTransform =
+                ui::Transform(inverseOrientation, width, height) * displayInfo.transform;
+        t = t * target.displayTransform;
+    }
     target.setDefaultPointerTransform(t);
     inputTargets.push_back(target);
 }
@@ -3250,9 +3236,7 @@
                                                      motionEntry.xPrecision, motionEntry.yPrecision,
                                                      motionEntry.xCursorPosition,
                                                      motionEntry.yCursorPosition,
-                                                     dispatchEntry->displayOrientation,
-                                                     dispatchEntry->displaySize.x,
-                                                     dispatchEntry->displaySize.y,
+                                                     dispatchEntry->rawTransform,
                                                      motionEntry.downTime, motionEntry.eventTime,
                                                      motionEntry.pointerCount,
                                                      motionEntry.pointerProperties, usingCoords);
@@ -3981,14 +3965,14 @@
             mLock.unlock();
 
             MotionEvent event;
-            ui::Transform transform;
+            ui::Transform identityTransform;
             event.initialize(args->id, args->deviceId, args->source, args->displayId, INVALID_HMAC,
                              args->action, args->actionButton, args->flags, args->edgeFlags,
-                             args->metaState, args->buttonState, args->classification, transform,
-                             args->xPrecision, args->yPrecision, args->xCursorPosition,
-                             args->yCursorPosition, ui::Transform::ROT_0, INVALID_DISPLAY_SIZE,
-                             INVALID_DISPLAY_SIZE, args->downTime, args->eventTime,
-                             args->pointerCount, args->pointerProperties, args->pointerCoords);
+                             args->metaState, args->buttonState, args->classification,
+                             identityTransform, args->xPrecision, args->yPrecision,
+                             args->xCursorPosition, args->yCursorPosition, identityTransform,
+                             args->downTime, args->eventTime, args->pointerCount,
+                             args->pointerProperties, args->pointerCoords);
 
             policyFlags |= POLICY_FLAG_FILTERED;
             if (!mPolicy->filterInputEvent(&event, policyFlags)) {
@@ -5479,9 +5463,9 @@
         TouchState& state = stateIt->second;
         std::shared_ptr<InputChannel> requestingChannel;
         std::optional<int32_t> foundDeviceId;
-        for (const TouchedMonitor& touchedMonitor : state.gestureMonitors) {
-            if (touchedMonitor.monitor.inputChannel->getConnectionToken() == token) {
-                requestingChannel = touchedMonitor.monitor.inputChannel;
+        for (const auto& monitor : state.gestureMonitors) {
+            if (monitor.inputChannel->getConnectionToken() == token) {
+                requestingChannel = monitor.inputChannel;
                 foundDeviceId = state.deviceId;
             }
         }
diff --git a/services/inputflinger/dispatcher/InputDispatcher.h b/services/inputflinger/dispatcher/InputDispatcher.h
index 4f6d0d2..51ec551 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.h
+++ b/services/inputflinger/dispatcher/InputDispatcher.h
@@ -516,18 +516,16 @@
     android::os::InputEventInjectionResult findTouchedWindowTargetsLocked(
             nsecs_t currentTime, const MotionEntry& entry, std::vector<InputTarget>& inputTargets,
             nsecs_t* nextWakeupTime, bool* outConflictingPointerActions) REQUIRES(mLock);
-    std::vector<TouchedMonitor> findTouchedGestureMonitorsLocked(int32_t displayId) const
-            REQUIRES(mLock);
-    std::vector<TouchedMonitor> selectResponsiveMonitorsLocked(
-            const std::vector<TouchedMonitor>& gestureMonitors) const REQUIRES(mLock);
+    std::vector<Monitor> selectResponsiveMonitorsLocked(
+            const std::vector<Monitor>& gestureMonitors) const REQUIRES(mLock);
 
     void addWindowTargetLocked(const sp<android::gui::WindowInfoHandle>& windowHandle,
                                int32_t targetFlags, BitSet32 pointerIds,
                                std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
-    void addMonitoringTargetLocked(const Monitor& monitor, float xOffset, float yOffset,
+    void addMonitoringTargetLocked(const Monitor& monitor, int32_t displayId,
                                    std::vector<InputTarget>& inputTargets) REQUIRES(mLock);
-    void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId,
-                                          float xOffset = 0, float yOffset = 0) REQUIRES(mLock);
+    void addGlobalMonitoringTargetsLocked(std::vector<InputTarget>& inputTargets, int32_t displayId)
+            REQUIRES(mLock);
     void pokeUserActivityLocked(const EventEntry& eventEntry) REQUIRES(mLock);
     bool checkInjectionPermission(const sp<android::gui::WindowInfoHandle>& windowHandle,
                                   const InjectionState* injectionState);
diff --git a/services/inputflinger/dispatcher/InputTarget.h b/services/inputflinger/dispatcher/InputTarget.h
index 7c463c8..5b76eee 100644
--- a/services/inputflinger/dispatcher/InputTarget.h
+++ b/services/inputflinger/dispatcher/InputTarget.h
@@ -101,11 +101,8 @@
     // (ignored for KeyEvents)
     float globalScaleFactor = 1.0f;
 
-    // Current display orientation
-    uint32_t displayOrientation = ui::Transform::ROT_0;
-
-    // Display-size in its natural rotation. Used for compatibility transform of raw coordinates.
-    int2 displaySize = {INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE};
+    // Current display transform. Used for compatibility for raw coordinates.
+    ui::Transform displayTransform;
 
     // The subset of pointer ids to include in motion events dispatched to this input target
     // if FLAG_SPLIT is set.
diff --git a/services/inputflinger/dispatcher/Monitor.cpp b/services/inputflinger/dispatcher/Monitor.cpp
index bbce759..43a82d5 100644
--- a/services/inputflinger/dispatcher/Monitor.cpp
+++ b/services/inputflinger/dispatcher/Monitor.cpp
@@ -22,8 +22,4 @@
 Monitor::Monitor(const std::shared_ptr<InputChannel>& inputChannel, int32_t pid)
       : inputChannel(inputChannel), pid(pid) {}
 
-// --- TouchedMonitor ---
-TouchedMonitor::TouchedMonitor(const Monitor& monitor, float xOffset, float yOffset)
-      : monitor(monitor), xOffset(xOffset), yOffset(yOffset) {}
-
 } // namespace android::inputdispatcher
diff --git a/services/inputflinger/dispatcher/Monitor.h b/services/inputflinger/dispatcher/Monitor.h
index 7be0760..365d5be 100644
--- a/services/inputflinger/dispatcher/Monitor.h
+++ b/services/inputflinger/dispatcher/Monitor.h
@@ -29,15 +29,6 @@
     explicit Monitor(const std::shared_ptr<InputChannel>& inputChannel, int32_t pid);
 };
 
-// For tracking the offsets we need to apply when adding gesture monitor targets.
-struct TouchedMonitor {
-    Monitor monitor;
-    float xOffset = 0.f;
-    float yOffset = 0.f;
-
-    explicit TouchedMonitor(const Monitor& monitor, float xOffset, float yOffset);
-};
-
 } // namespace android::inputdispatcher
 
 #endif // _UI_INPUT_INPUTDISPATCHER_MONITOR_H
diff --git a/services/inputflinger/dispatcher/TouchState.cpp b/services/inputflinger/dispatcher/TouchState.cpp
index 4a50a68..759b3e7 100644
--- a/services/inputflinger/dispatcher/TouchState.cpp
+++ b/services/inputflinger/dispatcher/TouchState.cpp
@@ -75,7 +75,7 @@
     windows.push_back(touchedWindow);
 }
 
-void TouchState::addGestureMonitors(const std::vector<TouchedMonitor>& newMonitors) {
+void TouchState::addGestureMonitors(const std::vector<Monitor>& newMonitors) {
     const size_t newSize = gestureMonitors.size() + newMonitors.size();
     gestureMonitors.reserve(newSize);
     gestureMonitors.insert(std::end(gestureMonitors), std::begin(newMonitors),
diff --git a/services/inputflinger/dispatcher/TouchState.h b/services/inputflinger/dispatcher/TouchState.h
index 7dcf55d..4a62051 100644
--- a/services/inputflinger/dispatcher/TouchState.h
+++ b/services/inputflinger/dispatcher/TouchState.h
@@ -36,7 +36,7 @@
     int32_t displayId; // id to the display that currently has a touch, others are rejected
     std::vector<TouchedWindow> windows;
 
-    std::vector<TouchedMonitor> gestureMonitors;
+    std::vector<Monitor> gestureMonitors;
 
     TouchState();
     ~TouchState();
@@ -45,7 +45,7 @@
     void addOrUpdateWindow(const sp<android::gui::WindowInfoHandle>& windowHandle,
                            int32_t targetFlags, BitSet32 pointerIds);
     void addPortalWindow(const sp<android::gui::WindowInfoHandle>& windowHandle);
-    void addGestureMonitors(const std::vector<TouchedMonitor>& monitors);
+    void addGestureMonitors(const std::vector<Monitor>& monitors);
     void removeWindowByToken(const sp<IBinder>& token);
     void filterNonAsIsTouchWindows();
     void filterNonMonitors();
diff --git a/services/inputflinger/reader/Macros.h b/services/inputflinger/reader/Macros.h
index 827e31a..0dfe7f1 100644
--- a/services/inputflinger/reader/Macros.h
+++ b/services/inputflinger/reader/Macros.h
@@ -31,7 +31,7 @@
 #define DEBUG_VIRTUAL_KEYS 0
 
 // Log debug messages about pointers.
-#define DEBUG_POINTERS 0
+static constexpr bool DEBUG_POINTERS = false;
 
 // Log debug messages about pointer assignment calculations.
 #define DEBUG_POINTER_ASSIGNMENT 0
diff --git a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
index fab7f4c..4bd1cd8 100644
--- a/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
+++ b/services/inputflinger/reader/mapper/MultiTouchInputMapper.cpp
@@ -95,13 +95,13 @@
         }
 
         if (mCurrentSlot < 0 || size_t(mCurrentSlot) >= mSlotCount) {
-#if DEBUG_POINTERS
-            if (newSlot) {
-                ALOGW("MultiTouch device emitted invalid slot index %d but it "
-                      "should be between 0 and %zd; ignoring this slot.",
-                      mCurrentSlot, mSlotCount - 1);
+            if (DEBUG_POINTERS) {
+                if (newSlot) {
+                    ALOGW("MultiTouch device emitted invalid slot index %d but it "
+                          "should be between 0 and %zd; ignoring this slot.",
+                          mCurrentSlot, mSlotCount - 1);
+                }
             }
-#endif
         } else {
             Slot* slot = &mSlots[mCurrentSlot];
             // If mUsingSlotsProtocol is true, it means the raw pointer has axis info of
@@ -273,19 +273,19 @@
             if (id) {
                 outState->rawPointerData.canceledIdBits.markBit(id.value());
             }
-#if DEBUG_POINTERS
-            ALOGI("Stop processing slot %zu for it received a palm event from device %s", inIndex,
-                  getDeviceName().c_str());
-#endif
+            if (DEBUG_POINTERS) {
+                ALOGI("Stop processing slot %zu for it received a palm event from device %s",
+                      inIndex, getDeviceName().c_str());
+            }
             continue;
         }
 
         if (outCount >= MAX_POINTERS) {
-#if DEBUG_POINTERS
-            ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; "
-                  "ignoring the rest.",
-                  getDeviceName().c_str(), MAX_POINTERS);
-#endif
+            if (DEBUG_POINTERS) {
+                ALOGD("MultiTouch device %s emitted more than maximum of %d pointers; "
+                      "ignoring the rest.",
+                      getDeviceName().c_str(), MAX_POINTERS);
+            }
             break; // too many fingers!
         }
 
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 903f337..e9d45b2 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -542,8 +542,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      /*action*/ -1, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
-                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
+                     ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -556,8 +556,7 @@
                              (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
-                     ARBITRARY_TIME, ARBITRARY_TIME,
+                     identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -569,8 +568,7 @@
                              (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
-                     ARBITRARY_TIME, ARBITRARY_TIME,
+                     identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -583,8 +581,7 @@
                              (1 << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
-                     ARBITRARY_TIME, ARBITRARY_TIME,
+                     identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -596,8 +593,7 @@
                              (~0U << AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
                      0, 0, edgeFlags, metaState, 0, classification, identityTransform, 0, 0,
                      AMOTION_EVENT_INVALID_CURSOR_POSITION, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     ui::Transform::ROT_0, INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE,
-                     ARBITRARY_TIME, ARBITRARY_TIME,
+                     identityTransform, ARBITRARY_TIME, ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -608,8 +604,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
-                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
+                     ARBITRARY_TIME,
                      /*pointerCount*/ 0, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -619,8 +615,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
-                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
+                     ARBITRARY_TIME,
                      /*pointerCount*/ MAX_POINTERS + 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -632,8 +628,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
-                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
+                     ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -644,8 +640,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
-                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
+                     ARBITRARY_TIME,
                      /*pointerCount*/ 1, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -658,8 +654,8 @@
     event.initialize(InputEvent::nextId(), DEVICE_ID, source, DISPLAY_ID, INVALID_HMAC,
                      AMOTION_EVENT_ACTION_DOWN, 0, 0, edgeFlags, metaState, 0, classification,
                      identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                     AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
-                     INVALID_DISPLAY_SIZE, INVALID_DISPLAY_SIZE, ARBITRARY_TIME, ARBITRARY_TIME,
+                     AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, ARBITRARY_TIME,
+                     ARBITRARY_TIME,
                      /*pointerCount*/ 2, pointerProperties, pointerCoords);
     ASSERT_EQ(InputEventInjectionResult::FAILED,
               mDispatcher->injectInputEvent(&event, INJECTOR_PID, INJECTOR_UID,
@@ -1296,9 +1292,8 @@
                          mAction, mActionButton, mFlags, /* edgeFlags */ 0, AMETA_NONE,
                          mButtonState, MotionClassification::NONE, identityTransform,
                          /* xPrecision */ 0, /* yPrecision */ 0, mRawXCursorPosition,
-                         mRawYCursorPosition, mDisplayOrientation, mDisplayWidth, mDisplayHeight,
-                         mEventTime, mEventTime, mPointers.size(), pointerProperties.data(),
-                         pointerCoords.data());
+                         mRawYCursorPosition, identityTransform, mEventTime, mEventTime,
+                         mPointers.size(), pointerProperties.data(), pointerCoords.data());
 
         return event;
     }
@@ -1313,9 +1308,6 @@
     int32_t mFlags{0};
     float mRawXCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
     float mRawYCursorPosition{AMOTION_EVENT_INVALID_CURSOR_POSITION};
-    uint32_t mDisplayOrientation{ui::Transform::ROT_0};
-    int32_t mDisplayWidth{INVALID_DISPLAY_SIZE};
-    int32_t mDisplayHeight{INVALID_DISPLAY_SIZE};
 
     std::vector<PointerBuilder> mPointers;
 };
@@ -3622,8 +3614,7 @@
                          DISPLAY_ID, INVALID_HMAC, AMOTION_EVENT_ACTION_DOWN, 0, 0,
                          AMOTION_EVENT_EDGE_FLAG_NONE, AMETA_NONE, 0, MotionClassification::NONE,
                          identityTransform, 0, 0, AMOTION_EVENT_INVALID_CURSOR_POSITION,
-                         AMOTION_EVENT_INVALID_CURSOR_POSITION, ui::Transform::ROT_0,
-                         0 /*INVALID_DISPLAY_SIZE*/, 0 /*INVALID_DISPLAY_SIZE*/, eventTime,
+                         AMOTION_EVENT_INVALID_CURSOR_POSITION, identityTransform, eventTime,
                          eventTime,
                          /*pointerCount*/ 1, pointerProperties, pointerCoords);
 
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e4f642e..d51db88 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -17,7 +17,6 @@
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
 #pragma clang diagnostic push
 #pragma clang diagnostic ignored "-Wconversion"
-#pragma clang diagnostic ignored "-Wextra"
 
 #undef LOG_TAG
 #define LOG_TAG "BufferQueueLayer"
@@ -171,7 +170,7 @@
         expectedPresentTime = 0;
     }
 
-    for (int i = 1; i < mQueueItems.size(); i++) {
+    for (size_t i = 1; i < mQueueItems.size(); i++) {
         const bool fenceSignaled =
                 mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
         if (!fenceSignaled) {
@@ -243,7 +242,7 @@
     uint64_t lastSignaledFrameNumber = mLastFrameNumberReceived;
     {
         Mutex::Autolock lock(mQueueItemLock);
-        for (int i = 0; i < mQueueItems.size(); i++) {
+        for (size_t i = 0; i < mQueueItems.size(); i++) {
             bool fenceSignaled =
                     mQueueItems[i].item.mFenceTime->getSignalTime() != Fence::SIGNAL_TIME_PENDING;
             if (!fenceSignaled) {
@@ -629,4 +628,4 @@
 } // namespace android
 
 // TODO(b/129481165): remove the #pragma below and fix conversion issues
-#pragma clang diagnostic pop // ignored "-Wconversion -Wextra"
+#pragma clang diagnostic pop // ignored "-Wconversion"
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index ef6f115..d549fe9 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -135,6 +135,7 @@
     mDrawingState.postTime = -1;
     mDrawingState.destinationFrame.makeInvalid();
     mDrawingState.isTrustedOverlay = false;
+    mDrawingState.dropInputMode = gui::DropInputMode::NONE;
 
     if (args.flags & ISurfaceComposerClient::eNoColorFill) {
         // Set an invalid color so there is no color fill.
@@ -2541,6 +2542,14 @@
     return handle->owner;
 }
 
+bool Layer::setDropInputMode(gui::DropInputMode mode) {
+    if (mDrawingState.dropInputMode == mode) {
+        return false;
+    }
+    mDrawingState.dropInputMode = mode;
+    return true;
+}
+
 // ---------------------------------------------------------------------------
 
 std::ostream& operator<<(std::ostream& stream, const Layer::FrameRate& rate) {
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 3c3c7d0..b70d5d4 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -17,6 +17,7 @@
 
 #pragma once
 
+#include <android/gui/DropInputMode.h>
 #include <compositionengine/LayerFE.h>
 #include <gui/BufferQueue.h>
 #include <gui/ISurfaceComposerClient.h>
@@ -277,6 +278,8 @@
         Rect destinationFrame;
 
         sp<IBinder> releaseBufferEndpoint;
+
+        gui::DropInputMode dropInputMode;
     };
 
     /*
@@ -442,6 +445,8 @@
     virtual bool setFrameRateSelectionPriority(int32_t priority);
     virtual bool setFixedTransformHint(ui::Transform::RotationFlags fixedTransformHint);
     virtual void setAutoRefresh(bool /* autoRefresh */) {}
+    bool setDropInputMode(gui::DropInputMode);
+
     //  If the variable is not set on the layer, it traverses up the tree to inherit the frame
     //  rate priority from its parent.
     virtual int32_t getFrameRateSelectionPriority() const;
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
index b00423e..3f6bd6f 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.cpp
@@ -133,27 +133,10 @@
     return true;
 }
 
-float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer,
-                                                    const RefreshRate& refreshRate,
-                                                    bool isSeamlessSwitch) const {
-    if (!isVoteAllowed(layer, refreshRate)) {
-        return 0;
-    }
-
+float RefreshRateConfigs::calculateNonExactMatchingLayerScoreLocked(
+        const LayerRequirement& layer, const RefreshRate& refreshRate) const {
     constexpr float kScoreForFractionalPairs = .8f;
 
-    // Slightly prefer seamless switches.
-    constexpr float kSeamedSwitchPenalty = 0.95f;
-    const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
-
-    // If the layer wants Max, give higher score to the higher refresh rate
-    if (layer.vote == LayerVoteType::Max) {
-        const auto ratio = refreshRate.getFps().getValue() /
-                mAppRequestRefreshRates.back()->getFps().getValue();
-        // use ratio^2 to get a lower score the more we get further from peak
-        return ratio * ratio;
-    }
-
     const auto displayPeriod = refreshRate.getVsyncPeriod();
     const auto layerPeriod = layer.desiredRefreshRate.getPeriodNsecs();
     if (layer.vote == LayerVoteType::ExplicitDefault) {
@@ -178,7 +161,7 @@
     if (layer.vote == LayerVoteType::ExplicitExactOrMultiple ||
         layer.vote == LayerVoteType::Heuristic) {
         if (isFractionalPairOrMultiple(refreshRate.getFps(), layer.desiredRefreshRate)) {
-            return kScoreForFractionalPairs * seamlessness;
+            return kScoreForFractionalPairs;
         }
 
         // Calculate how many display vsyncs we need to present a single frame for this
@@ -188,7 +171,7 @@
         static constexpr size_t MAX_FRAMES_TO_FIT = 10; // Stop calculating when score < 0.1
         if (displayFramesRemainder == 0) {
             // Layer desired refresh rate matches the display rate.
-            return 1.0f * seamlessness;
+            return 1.0f;
         }
 
         if (displayFramesQuotient == 0) {
@@ -206,7 +189,29 @@
             iter++;
         }
 
-        return (1.0f / iter) * seamlessness;
+        return (1.0f / iter);
+    }
+
+    return 0;
+}
+
+float RefreshRateConfigs::calculateLayerScoreLocked(const LayerRequirement& layer,
+                                                    const RefreshRate& refreshRate,
+                                                    bool isSeamlessSwitch) const {
+    if (!isVoteAllowed(layer, refreshRate)) {
+        return 0;
+    }
+
+    // Slightly prefer seamless switches.
+    constexpr float kSeamedSwitchPenalty = 0.95f;
+    const float seamlessness = isSeamlessSwitch ? 1.0f : kSeamedSwitchPenalty;
+
+    // If the layer wants Max, give higher score to the higher refresh rate
+    if (layer.vote == LayerVoteType::Max) {
+        const auto ratio = refreshRate.getFps().getValue() /
+                mAppRequestRefreshRates.back()->getFps().getValue();
+        // use ratio^2 to get a lower score the more we get further from peak
+        return ratio * ratio;
     }
 
     if (layer.vote == LayerVoteType::ExplicitExact) {
@@ -221,7 +226,18 @@
         return divider == 1;
     }
 
-    return 0;
+    // If the layer frame rate is a divider of the refresh rate it should score
+    // the highest score.
+    if (getFrameRateDivider(refreshRate.getFps(), layer.desiredRefreshRate) > 0) {
+        return 1.0f * seamlessness;
+    }
+
+    // The layer frame rate is not a divider of the refresh rate,
+    // there is a small penalty attached to the score to favor the frame rates
+    // the exactly matches the display refresh rate or a multiple.
+    constexpr float kNonExactMatchingPenalty = 0.99f;
+    return calculateNonExactMatchingLayerScoreLocked(layer, refreshRate) * seamlessness *
+            kNonExactMatchingPenalty;
 }
 
 struct RefreshRateScore {
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index 3713587..ffaa029 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -409,6 +409,9 @@
     float calculateLayerScoreLocked(const LayerRequirement&, const RefreshRate&,
                                     bool isSeamlessSwitch) const REQUIRES(mLock);
 
+    float calculateNonExactMatchingLayerScoreLocked(const LayerRequirement&,
+                                                    const RefreshRate&) const REQUIRES(mLock);
+
     void updateDisplayModes(const DisplayModes& mode, DisplayModeId currentModeId) EXCLUDES(mLock);
 
     // The list of refresh rates, indexed by display modes ID. This may change after this
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index bc2ef40..da2204e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -1716,7 +1716,15 @@
 
 void SurfaceFlinger::onComposerHalVsync(hal::HWDisplayId hwcDisplayId, int64_t timestamp,
                                         std::optional<hal::VsyncPeriodNanos> vsyncPeriod) {
-    ATRACE_CALL();
+    const std::string tracePeriod = [vsyncPeriod]() {
+        if (ATRACE_ENABLED() && vsyncPeriod) {
+            std::stringstream ss;
+            ss << "(" << *vsyncPeriod << ")";
+            return ss.str();
+        }
+        return std::string();
+    }();
+    ATRACE_FORMAT("onComposerHalVsync%s", tracePeriod.c_str());
 
     Mutex::Autolock lock(mStateLock);
     const auto displayId = getHwComposer().toPhysicalDisplayId(hwcDisplayId);
@@ -4153,6 +4161,16 @@
             flags |= eTraversalNeeded;
         }
     }
+    if (what & layer_state_t::eDropInputModeChanged) {
+        if (privileged) {
+            if (layer->setDropInputMode(s.dropInputMode)) {
+                flags |= eTraversalNeeded;
+                mInputInfoChanged = true;
+            }
+        } else {
+            ALOGE("Attempt to update DropInputMode without permission ACCESS_SURFACE_FLINGER");
+        }
+    }
     // This has to happen after we reparent children because when we reparent to null we remove
     // child layers from current state and remove its relative z. If the children are reparented in
     // the same transaction, then we have to make sure we reparent the children first so we do not
@@ -5152,7 +5170,8 @@
             continue;
         }
 
-        StringAppendF(&result, "Display %s HWC layers:\n", to_string(*displayId).c_str());
+        StringAppendF(&result, "Display %s (%s) HWC layers:\n", to_string(*displayId).c_str(),
+                      (isDisplayActiveLocked(display) ? "active" : "inactive"));
         Layer::miniDumpHeader(result);
 
         const DisplayDevice& ref = *display;
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 5960be1..141d7ac 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -1016,7 +1016,7 @@
 
     sp<DisplayDevice> getDisplayWithInputByLayer(Layer* layer) const REQUIRES(mStateLock);
 
-    bool isDisplayActiveLocked(const sp<const DisplayDevice>& display) REQUIRES(mStateLock) {
+    bool isDisplayActiveLocked(const sp<const DisplayDevice>& display) const REQUIRES(mStateLock) {
         return display->getDisplayToken() == mActiveDisplayToken;
     }
 
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
index 618c10d..a8e3e5e 100644
--- a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -175,7 +175,6 @@
     RefreshRate mExpected30Config = {mConfig30, RefreshRate::ConstructorTag(0)};
     RefreshRate mExpected120Config = {mConfig120, RefreshRate::ConstructorTag(0)};
 
-private:
     DisplayModePtr createDisplayMode(DisplayModeId modeId, int32_t group, int64_t vsyncPeriod,
                                      ui::Size resolution = ui::Size());
 };
@@ -2179,6 +2178,44 @@
               refreshRateConfigs->getBestRefreshRate(layers, {.touch = false, .idle = false}));
 }
 
+// b/190578904
+TEST_F(RefreshRateConfigsTest, getBestRefreshRate_deviceWithCloseRefreshRates) {
+    constexpr int kMinRefreshRate = 10;
+    constexpr int kMaxRefreshRate = 240;
+
+    DisplayModes displayModes;
+    for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
+        constexpr int32_t kGroup = 0;
+        const auto refreshRate = Fps(static_cast<float>(fps));
+        displayModes.push_back(
+                createDisplayMode(DisplayModeId(fps), kGroup, refreshRate.getPeriodNsecs()));
+    }
+
+    const RefreshRateConfigs::GlobalSignals globalSignals = {.touch = false, .idle = false};
+    auto refreshRateConfigs =
+            std::make_unique<RefreshRateConfigs>(displayModes,
+                                                 /*currentConfigId=*/displayModes[0]->getId());
+
+    auto layers = std::vector<LayerRequirement>{LayerRequirement{.weight = 1.0f}};
+    const auto testRefreshRate = [&](Fps fps, LayerVoteType vote) {
+        layers[0].desiredRefreshRate = fps;
+        layers[0].vote = vote;
+        EXPECT_EQ(fps.getIntValue(),
+                  refreshRateConfigs->getBestRefreshRate(layers, globalSignals)
+                          .getFps()
+                          .getIntValue())
+                << "Failed for " << RefreshRateConfigs::layerVoteTypeString(vote);
+    };
+
+    for (int fps = kMinRefreshRate; fps < kMaxRefreshRate; fps++) {
+        const auto refreshRate = Fps(static_cast<float>(fps));
+        testRefreshRate(refreshRate, LayerVoteType::Heuristic);
+        testRefreshRate(refreshRate, LayerVoteType::ExplicitDefault);
+        testRefreshRate(refreshRate, LayerVoteType::ExplicitExactOrMultiple);
+        testRefreshRate(refreshRate, LayerVoteType::ExplicitExact);
+    }
+}
+
 TEST_F(RefreshRateConfigsTest, testComparisonOperator) {
     EXPECT_TRUE(mExpected60Config < mExpected90Config);
     EXPECT_FALSE(mExpected60Config < mExpected60Config);