Merge changes from topic "move-input-rotation-to-native"

* changes:
  InputDispatcherPolicy: Transform incoming/outgoing events
  TouchInputMapper: Block touches outside logical display
diff --git a/cmds/lshal/PipeRelay.cpp b/cmds/lshal/PipeRelay.cpp
index 0c3fb96..863490d 100644
--- a/cmds/lshal/PipeRelay.cpp
+++ b/cmds/lshal/PipeRelay.cpp
@@ -82,6 +82,7 @@
                 continue;
             }
             out->write(buffer, n);
+            continue;
         }
         if (pfd[0].revents & POLLHUP) {
             break;
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/RpcCertificateUtils.cpp b/libs/binder/RpcCertificateUtils.cpp
deleted file mode 100644
index d91736c..0000000
--- a/libs/binder/RpcCertificateUtils.cpp
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * 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.
- */
-
-#define LOG_TAG "RpcCertificateUtils"
-#include <log/log.h>
-
-#include <binder/RpcCertificateUtils.h>
-
-#include "Utils.h"
-
-namespace android {
-
-namespace {
-
-bssl::UniquePtr<X509> fromPem(const std::vector<uint8_t>& cert) {
-    if (cert.size() > std::numeric_limits<int>::max()) return nullptr;
-    bssl::UniquePtr<BIO> certBio(BIO_new_mem_buf(cert.data(), static_cast<int>(cert.size())));
-    return bssl::UniquePtr<X509>(PEM_read_bio_X509(certBio.get(), nullptr, nullptr, nullptr));
-}
-
-bssl::UniquePtr<X509> fromDer(const std::vector<uint8_t>& cert) {
-    if (cert.size() > std::numeric_limits<long>::max()) return nullptr;
-    const unsigned char* data = cert.data();
-    auto expectedEnd = data + cert.size();
-    bssl::UniquePtr<X509> ret(d2i_X509(nullptr, &data, static_cast<long>(cert.size())));
-    if (data != expectedEnd) {
-        ALOGE("%s: %td bytes remaining!", __PRETTY_FUNCTION__, expectedEnd - data);
-        return nullptr;
-    }
-    return ret;
-}
-
-} // namespace
-
-bssl::UniquePtr<X509> deserializeCertificate(const std::vector<uint8_t>& cert,
-                                             RpcCertificateFormat format) {
-    switch (format) {
-        case RpcCertificateFormat::PEM:
-            return fromPem(cert);
-        case RpcCertificateFormat::DER:
-            return fromDer(cert);
-    }
-    LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
-}
-
-std::vector<uint8_t> serializeCertificate(X509* x509, RpcCertificateFormat format) {
-    bssl::UniquePtr<BIO> certBio(BIO_new(BIO_s_mem()));
-    switch (format) {
-        case RpcCertificateFormat::PEM: {
-            TEST_AND_RETURN({}, PEM_write_bio_X509(certBio.get(), x509));
-        } break;
-        case RpcCertificateFormat::DER: {
-            TEST_AND_RETURN({}, i2d_X509_bio(certBio.get(), x509));
-        } break;
-        default: {
-            LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
-        }
-    }
-    const uint8_t* data;
-    size_t len;
-    TEST_AND_RETURN({}, BIO_mem_contents(certBio.get(), &data, &len));
-    return std::vector<uint8_t>(data, data + len);
-}
-
-} // namespace android
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/RpcTlsUtils.cpp b/libs/binder/RpcTlsUtils.cpp
new file mode 100644
index 0000000..f3ca02a
--- /dev/null
+++ b/libs/binder/RpcTlsUtils.cpp
@@ -0,0 +1,111 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "RpcTlsUtils"
+#include <log/log.h>
+
+#include <binder/RpcTlsUtils.h>
+
+#include "Utils.h"
+
+namespace android {
+
+namespace {
+
+static_assert(sizeof(unsigned char) == sizeof(uint8_t));
+
+template <typename PemReadBioFn,
+          typename T = std::remove_pointer_t<std::invoke_result_t<
+                  PemReadBioFn, BIO*, std::nullptr_t, std::nullptr_t, std::nullptr_t>>>
+bssl::UniquePtr<T> fromPem(const std::vector<uint8_t>& data, PemReadBioFn fn) {
+    if (data.size() > std::numeric_limits<int>::max()) return nullptr;
+    bssl::UniquePtr<BIO> bio(BIO_new_mem_buf(data.data(), static_cast<int>(data.size())));
+    return bssl::UniquePtr<T>(fn(bio.get(), nullptr, nullptr, nullptr));
+}
+
+template <typename D2iFn,
+          typename T = std::remove_pointer_t<
+                  std::invoke_result_t<D2iFn, std::nullptr_t, const unsigned char**, long>>>
+bssl::UniquePtr<T> fromDer(const std::vector<uint8_t>& data, D2iFn fn) {
+    if (data.size() > std::numeric_limits<long>::max()) return nullptr;
+    const unsigned char* dataPtr = data.data();
+    auto expectedEnd = dataPtr + data.size();
+    bssl::UniquePtr<T> ret(fn(nullptr, &dataPtr, static_cast<long>(data.size())));
+    if (dataPtr != expectedEnd) {
+        ALOGE("%s: %td bytes remaining!", __PRETTY_FUNCTION__, expectedEnd - dataPtr);
+        return nullptr;
+    }
+    return ret;
+}
+
+template <typename T, typename WriteBioFn = int (*)(BIO*, T*)>
+std::vector<uint8_t> serialize(T* object, WriteBioFn writeBio) {
+    bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+    TEST_AND_RETURN({}, writeBio(bio.get(), object));
+    const uint8_t* data;
+    size_t len;
+    TEST_AND_RETURN({}, BIO_mem_contents(bio.get(), &data, &len));
+    return std::vector<uint8_t>(data, data + len);
+}
+
+} // namespace
+
+bssl::UniquePtr<X509> deserializeCertificate(const std::vector<uint8_t>& data,
+                                             RpcCertificateFormat format) {
+    switch (format) {
+        case RpcCertificateFormat::PEM:
+            return fromPem(data, PEM_read_bio_X509);
+        case RpcCertificateFormat::DER:
+            return fromDer(data, d2i_X509);
+    }
+    LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+}
+
+std::vector<uint8_t> serializeCertificate(X509* x509, RpcCertificateFormat format) {
+    switch (format) {
+        case RpcCertificateFormat::PEM:
+            return serialize(x509, PEM_write_bio_X509);
+        case RpcCertificateFormat::DER:
+            return serialize(x509, i2d_X509_bio);
+    }
+    LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+}
+
+bssl::UniquePtr<EVP_PKEY> deserializeUnencryptedPrivatekey(const std::vector<uint8_t>& data,
+                                                           RpcKeyFormat format) {
+    switch (format) {
+        case RpcKeyFormat::PEM:
+            return fromPem(data, PEM_read_bio_PrivateKey);
+        case RpcKeyFormat::DER:
+            return fromDer(data, d2i_AutoPrivateKey);
+    }
+    LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+}
+
+std::vector<uint8_t> serializeUnencryptedPrivatekey(EVP_PKEY* pkey, RpcKeyFormat format) {
+    switch (format) {
+        case RpcKeyFormat::PEM:
+            return serialize(pkey, [](BIO* bio, EVP_PKEY* pkey) {
+                return PEM_write_bio_PrivateKey(bio, pkey, nullptr /* enc */, nullptr /* kstr */,
+                                                0 /* klen */, nullptr, nullptr);
+            });
+        case RpcKeyFormat::DER:
+            return serialize(pkey, i2d_PrivateKey_bio);
+    }
+    LOG_ALWAYS_FATAL("Unsupported format %d", static_cast<int>(format));
+}
+
+} // namespace android
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/RpcCertificateUtils.h b/libs/binder/include/binder/RpcKeyFormat.h
similarity index 63%
copy from libs/binder/include_tls/binder/RpcCertificateUtils.h
copy to libs/binder/include/binder/RpcKeyFormat.h
index 8d07835..5099c2e 100644
--- a/libs/binder/include_tls/binder/RpcCertificateUtils.h
+++ b/libs/binder/include/binder/RpcKeyFormat.h
@@ -14,21 +14,28 @@
  * limitations under the License.
  */
 
-// Utilities for serializing and deserializing X509 certificates.
+// Formats for serializing TLS private keys.
 
 #pragma once
 
-#include <vector>
-
-#include <openssl/ssl.h>
-
-#include <binder/RpcCertificateFormat.h>
+#include <string>
 
 namespace android {
 
-bssl::UniquePtr<X509> deserializeCertificate(const std::vector<uint8_t>& cert,
-                                             RpcCertificateFormat format);
+enum class RpcKeyFormat {
+    PEM,
+    DER,
+};
 
-std::vector<uint8_t> serializeCertificate(X509* x509, RpcCertificateFormat format);
+static inline std::string PrintToString(RpcKeyFormat format) {
+    switch (format) {
+        case RpcKeyFormat::PEM:
+            return "PEM";
+        case RpcKeyFormat::DER:
+            return "DER";
+        default:
+            return "<unknown>";
+    }
+}
 
 } // 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_tls/binder/RpcCertificateVerifier.h b/libs/binder/include_tls/binder/RpcCertificateVerifier.h
index 97af31c..800e375 100644
--- a/libs/binder/include_tls/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 72%
rename from libs/binder/include_tls/binder/RpcCertificateUtils.h
rename to libs/binder/include_tls/binder/RpcTlsUtils.h
index 8d07835..591926b 100644
--- a/libs/binder/include_tls/binder/RpcCertificateUtils.h
+++ b/libs/binder/include_tls/binder/RpcTlsUtils.h
@@ -23,12 +23,20 @@
 #include <openssl/ssl.h>
 
 #include <binder/RpcCertificateFormat.h>
+#include <binder/RpcKeyFormat.h>
 
 namespace android {
 
-bssl::UniquePtr<X509> deserializeCertificate(const std::vector<uint8_t>& cert,
+bssl::UniquePtr<X509> deserializeCertificate(const std::vector<uint8_t>& data,
                                              RpcCertificateFormat format);
 
 std::vector<uint8_t> serializeCertificate(X509* x509, RpcCertificateFormat format);
 
+// Deserialize an un-encrypted private key.
+bssl::UniquePtr<EVP_PKEY> deserializeUnencryptedPrivatekey(const std::vector<uint8_t>& data,
+                                                           RpcKeyFormat format);
+
+// Serialize a private key in un-encrypted form.
+std::vector<uint8_t> serializeUnencryptedPrivatekey(EVP_PKEY* pkey, RpcKeyFormat format);
+
 } // namespace android
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/tests/Android.bp b/libs/binder/tests/Android.bp
index 1968058..23c1b14 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: [
@@ -172,6 +173,37 @@
     require_root: true,
 }
 
+cc_test {
+    name: "RpcTlsUtilsTest",
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+        android: {
+            test_suites: ["vts"],
+        },
+    },
+    defaults: [
+        "binder_test_defaults",
+        "libbinder_tls_shared_deps",
+    ],
+    srcs: [
+        "RpcAuthTesting.cpp",
+        "RpcTlsUtilsTest.cpp",
+    ],
+    shared_libs: [
+        "libbinder",
+        "libbase",
+        "libutils",
+        "liblog",
+    ],
+    static_libs: [
+        "libbinder_tls_static",
+    ],
+    test_suites: ["general-tests", "device-tests"],
+}
+
 cc_benchmark {
     name: "binderRpcBenchmark",
     defaults: ["binder_test_defaults"],
diff --git a/libs/binder/tests/RpcAuthTesting.cpp b/libs/binder/tests/RpcAuthTesting.cpp
new file mode 100644
index 0000000..c0587a2
--- /dev/null
+++ b/libs/binder/tests/RpcAuthTesting.cpp
@@ -0,0 +1,83 @@
+/*
+ * 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;
+}
+
+status_t RpcAuthPreSigned::configure(SSL_CTX* ctx) {
+    if (!SSL_CTX_use_PrivateKey(ctx, mPkey.get())) {
+        return INVALID_OPERATION;
+    }
+    if (!SSL_CTX_use_certificate(ctx, mCert.get())) {
+        return INVALID_OPERATION;
+    }
+    return OK;
+}
+
+} // namespace android
diff --git a/libs/binder/tests/RpcAuthTesting.h b/libs/binder/tests/RpcAuthTesting.h
new file mode 100644
index 0000000..c3c2df4
--- /dev/null
+++ b/libs/binder/tests/RpcAuthTesting.h
@@ -0,0 +1,49 @@
+/*
+ * 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;
+};
+
+class RpcAuthPreSigned : public RpcAuth {
+public:
+    RpcAuthPreSigned(bssl::UniquePtr<EVP_PKEY> pkey, bssl::UniquePtr<X509> cert)
+          : mPkey(std::move(pkey)), mCert(std::move(cert)) {}
+    status_t configure(SSL_CTX* ctx) override;
+
+private:
+    bssl::UniquePtr<EVP_PKEY> mPkey;
+    bssl::UniquePtr<X509> mCert;
+};
+
+} // 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/RpcTlsUtilsTest.cpp b/libs/binder/tests/RpcTlsUtilsTest.cpp
new file mode 100644
index 0000000..9b3078d
--- /dev/null
+++ b/libs/binder/tests/RpcTlsUtilsTest.cpp
@@ -0,0 +1,115 @@
+/*
+ * 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 <binder/RpcTlsUtils.h>
+#include <gtest/gtest.h>
+
+#include "RpcAuthTesting.h"
+
+namespace android {
+
+std::string toDebugString(EVP_PKEY* pkey) {
+    bssl::UniquePtr<BIO> bio(BIO_new(BIO_s_mem()));
+    int res = EVP_PKEY_print_public(bio.get(), pkey, 2, nullptr);
+    std::string buf = "\nEVP_PKEY_print_public -> " + std::to_string(res) + "\n";
+    if (BIO_write(bio.get(), buf.data(), buf.length()) <= 0) return {};
+    res = EVP_PKEY_print_private(bio.get(), pkey, 2, nullptr);
+    buf = "\nEVP_PKEY_print_private -> " + std::to_string(res);
+    if (BIO_write(bio.get(), buf.data(), buf.length()) <= 0) return {};
+    const uint8_t* data;
+    size_t len;
+    if (!BIO_mem_contents(bio.get(), &data, &len)) return {};
+    return std::string(reinterpret_cast<const char*>(data), len);
+}
+
+class RpcTlsUtilsKeyTest : public testing::TestWithParam<RpcKeyFormat> {
+public:
+    static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+        return PrintToString(info.param);
+    }
+};
+
+TEST_P(RpcTlsUtilsKeyTest, Test) {
+    auto pkey = makeKeyPairForSelfSignedCert();
+    ASSERT_NE(nullptr, pkey);
+    auto pkeyData = serializeUnencryptedPrivatekey(pkey.get(), GetParam());
+    auto deserializedPkey = deserializeUnencryptedPrivatekey(pkeyData, GetParam());
+    ASSERT_NE(nullptr, deserializedPkey);
+    EXPECT_EQ(1, EVP_PKEY_cmp(pkey.get(), deserializedPkey.get()))
+            << "expected: " << toDebugString(pkey.get())
+            << "\nactual: " << toDebugString(deserializedPkey.get());
+}
+
+INSTANTIATE_TEST_CASE_P(RpcTlsUtilsTest, RpcTlsUtilsKeyTest,
+                        testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER),
+                        RpcTlsUtilsKeyTest::PrintParamInfo);
+
+class RpcTlsUtilsCertTest : public testing::TestWithParam<RpcCertificateFormat> {
+public:
+    static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+        return PrintToString(info.param);
+    }
+};
+
+TEST_P(RpcTlsUtilsCertTest, Test) {
+    auto pkey = makeKeyPairForSelfSignedCert();
+    ASSERT_NE(nullptr, pkey);
+    // Make certificate from the original key in memory
+    auto cert = makeSelfSignedCert(pkey.get(), kCertValidSeconds);
+    ASSERT_NE(nullptr, cert);
+    auto certData = serializeCertificate(cert.get(), GetParam());
+    auto deserializedCert = deserializeCertificate(certData, GetParam());
+    ASSERT_NE(nullptr, deserializedCert);
+    EXPECT_EQ(0, X509_cmp(cert.get(), deserializedCert.get()));
+}
+
+INSTANTIATE_TEST_CASE_P(RpcTlsUtilsTest, RpcTlsUtilsCertTest,
+                        testing::Values(RpcCertificateFormat::PEM, RpcCertificateFormat::DER),
+                        RpcTlsUtilsCertTest::PrintParamInfo);
+
+class RpcTlsUtilsKeyAndCertTest
+      : public testing::TestWithParam<std::tuple<RpcKeyFormat, RpcCertificateFormat>> {
+public:
+    static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+        auto [keyFormat, certificateFormat] = info.param;
+        return "key_" + PrintToString(keyFormat) + "_cert_" + PrintToString(certificateFormat);
+    }
+};
+
+TEST_P(RpcTlsUtilsKeyAndCertTest, TestCertFromDeserializedKey) {
+    auto [keyFormat, certificateFormat] = GetParam();
+    auto pkey = makeKeyPairForSelfSignedCert();
+    ASSERT_NE(nullptr, pkey);
+    auto pkeyData = serializeUnencryptedPrivatekey(pkey.get(), keyFormat);
+    auto deserializedPkey = deserializeUnencryptedPrivatekey(pkeyData, keyFormat);
+    ASSERT_NE(nullptr, deserializedPkey);
+
+    // Make certificate from deserialized key loaded from bytes
+    auto cert = makeSelfSignedCert(deserializedPkey.get(), kCertValidSeconds);
+    ASSERT_NE(nullptr, cert);
+    auto certData = serializeCertificate(cert.get(), certificateFormat);
+    auto deserializedCert = deserializeCertificate(certData, certificateFormat);
+    ASSERT_NE(nullptr, deserializedCert);
+    EXPECT_EQ(0, X509_cmp(cert.get(), deserializedCert.get()));
+}
+
+INSTANTIATE_TEST_CASE_P(RpcTlsUtilsTest, RpcTlsUtilsKeyAndCertTest,
+                        testing::Combine(testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER),
+                                         testing::Values(RpcCertificateFormat::PEM,
+                                                         RpcCertificateFormat::DER)),
+                        RpcTlsUtilsKeyAndCertTest::PrintParamInfo);
+
+} // namespace android
diff --git a/libs/binder/tests/binderRpcTest.cpp b/libs/binder/tests/binderRpcTest.cpp
index 6bcf102..0e7e259 100644
--- a/libs/binder/tests/binderRpcTest.cpp
+++ b/libs/binder/tests/binderRpcTest.cpp
@@ -31,6 +31,7 @@
 #include <binder/ProcessState.h>
 #include <binder/RpcServer.h>
 #include <binder/RpcSession.h>
+#include <binder/RpcTlsUtils.h>
 #include <binder/RpcTransport.h>
 #include <binder/RpcTransportRaw.h>
 #include <binder/RpcTransportTls.h>
@@ -48,8 +49,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 +73,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 +82,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 +1042,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 +1063,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 +1095,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) {
@@ -1430,37 +1440,10 @@
 INSTANTIATE_TEST_CASE_P(BinderRpc, BinderRpcSimple, ::testing::ValuesIn(RpcSecurityValues()),
                         BinderRpcSimple::PrintTestParam);
 
-class RpcTransportTest
-      : public ::testing::TestWithParam<
-                std::tuple<SocketType, RpcSecurity, std::optional<RpcCertificateFormat>>> {
+class RpcTransportTestUtils {
 public:
+    using Param = std::tuple<SocketType, RpcSecurity, std::optional<RpcCertificateFormat>>;
     using ConnectToServer = std::function<base::unique_fd()>;
-    static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
-        auto [socketType, rpcSecurity, certificateFormat] = info.param;
-        auto ret = PrintToString(socketType) + "_" + newFactory(rpcSecurity)->toCString();
-        if (certificateFormat.has_value()) ret += "_" + PrintToString(*certificateFormat);
-        return ret;
-    }
-    static std::vector<ParamType> getRpcTranportTestParams() {
-        std::vector<RpcTransportTest::ParamType> ret;
-        for (auto socketType : testSocketTypes(false /* hasPreconnected */)) {
-            for (auto rpcSecurity : RpcSecurityValues()) {
-                switch (rpcSecurity) {
-                    case RpcSecurity::RAW: {
-                        ret.emplace_back(socketType, rpcSecurity, std::nullopt);
-                    } break;
-                    case RpcSecurity::TLS: {
-                        ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::PEM);
-                        ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::DER);
-                    } break;
-                }
-            }
-        }
-        return ret;
-    }
-    void TearDown() override {
-        for (auto& server : mServers) server->shutdownAndWait();
-    }
 
     // A server that handles client socket connections.
     class Server {
@@ -1468,8 +1451,10 @@
         explicit Server() {}
         Server(Server&&) = default;
         ~Server() { shutdownAndWait(); }
-        [[nodiscard]] AssertionResult setUp() {
-            auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+        [[nodiscard]] AssertionResult setUp(
+                const Param& param,
+                std::unique_ptr<RpcAuth> auth = std::make_unique<RpcAuthSelfSigned>()) {
+            auto [socketType, rpcSecurity, certificateFormat] = param;
             auto rpcServer = RpcServer::make(newFactory(rpcSecurity));
             rpcServer->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
             switch (socketType) {
@@ -1520,7 +1505,7 @@
             }
             mFd = rpcServer->releaseServer();
             if (!mFd.ok()) return AssertionFailure() << "releaseServer returns invalid fd";
-            mCtx = newFactory(rpcSecurity, mCertVerifier)->newServerCtx();
+            mCtx = newFactory(rpcSecurity, mCertVerifier, std::move(auth))->newServerCtx();
             if (mCtx == nullptr) return AssertionFailure() << "newServerCtx";
             mSetup = true;
             return AssertionSuccess();
@@ -1599,8 +1584,8 @@
     public:
         explicit Client(ConnectToServer connectToServer) : mConnectToServer(connectToServer) {}
         Client(Client&&) = default;
-        [[nodiscard]] AssertionResult setUp() {
-            auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+        [[nodiscard]] AssertionResult setUp(const Param& param) {
+            auto [socketType, rpcSecurity, certificateFormat] = param;
             mFdTrigger = FdTrigger::make();
             mCtx = newFactory(rpcSecurity, mCertVerifier)->newClientCtx();
             if (mCtx == nullptr) return AssertionFailure() << "newClientCtx";
@@ -1653,8 +1638,9 @@
 
     // Make A trust B.
     template <typename A, typename B>
-    status_t trust(A* a, B* b) {
-        auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+    static status_t trust(RpcSecurity rpcSecurity,
+                          std::optional<RpcCertificateFormat> certificateFormat, const A& a,
+                          const B& b) {
         if (rpcSecurity != RpcSecurity::TLS) return OK;
         LOG_ALWAYS_FATAL_IF(!certificateFormat.has_value());
         auto bCert = b->getCtx()->getCertificate(*certificateFormat);
@@ -1662,15 +1648,48 @@
     }
 
     static constexpr const char* kMessage = "hello";
-    std::vector<std::unique_ptr<Server>> mServers;
+};
+
+class RpcTransportTest : public testing::TestWithParam<RpcTransportTestUtils::Param> {
+public:
+    using Server = RpcTransportTestUtils::Server;
+    using Client = RpcTransportTestUtils::Client;
+    static inline std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+        auto [socketType, rpcSecurity, certificateFormat] = info.param;
+        auto ret = PrintToString(socketType) + "_" + newFactory(rpcSecurity)->toCString();
+        if (certificateFormat.has_value()) ret += "_" + PrintToString(*certificateFormat);
+        return ret;
+    }
+    static std::vector<ParamType> getRpcTranportTestParams() {
+        std::vector<ParamType> ret;
+        for (auto socketType : testSocketTypes(false /* hasPreconnected */)) {
+            for (auto rpcSecurity : RpcSecurityValues()) {
+                switch (rpcSecurity) {
+                    case RpcSecurity::RAW: {
+                        ret.emplace_back(socketType, rpcSecurity, std::nullopt);
+                    } break;
+                    case RpcSecurity::TLS: {
+                        ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::PEM);
+                        ret.emplace_back(socketType, rpcSecurity, RpcCertificateFormat::DER);
+                    } break;
+                }
+            }
+        }
+        return ret;
+    }
+    template <typename A, typename B>
+    status_t trust(const A& a, const B& b) {
+        auto [socketType, rpcSecurity, certificateFormat] = GetParam();
+        return RpcTransportTestUtils::trust(rpcSecurity, certificateFormat, a, b);
+    }
 };
 
 TEST_P(RpcTransportTest, GoodCertificate) {
-    auto server = mServers.emplace_back(std::make_unique<Server>()).get();
-    ASSERT_TRUE(server->setUp());
+    auto server = std::make_unique<Server>();
+    ASSERT_TRUE(server->setUp(GetParam()));
 
     Client client(server->getConnectToServerFn());
-    ASSERT_TRUE(client.setUp());
+    ASSERT_TRUE(client.setUp(GetParam()));
 
     ASSERT_EQ(OK, trust(&client, server));
     ASSERT_EQ(OK, trust(server, &client));
@@ -1680,13 +1699,13 @@
 }
 
 TEST_P(RpcTransportTest, MultipleClients) {
-    auto server = mServers.emplace_back(std::make_unique<Server>()).get();
-    ASSERT_TRUE(server->setUp());
+    auto server = std::make_unique<Server>();
+    ASSERT_TRUE(server->setUp(GetParam()));
 
     std::vector<Client> clients;
     for (int i = 0; i < 2; i++) {
         auto& client = clients.emplace_back(server->getConnectToServerFn());
-        ASSERT_TRUE(client.setUp());
+        ASSERT_TRUE(client.setUp(GetParam()));
         ASSERT_EQ(OK, trust(&client, server));
         ASSERT_EQ(OK, trust(server, &client));
     }
@@ -1698,11 +1717,11 @@
 TEST_P(RpcTransportTest, UntrustedServer) {
     auto [socketType, rpcSecurity, certificateFormat] = GetParam();
 
-    auto untrustedServer = mServers.emplace_back(std::make_unique<Server>()).get();
-    ASSERT_TRUE(untrustedServer->setUp());
+    auto untrustedServer = std::make_unique<Server>();
+    ASSERT_TRUE(untrustedServer->setUp(GetParam()));
 
     Client client(untrustedServer->getConnectToServerFn());
-    ASSERT_TRUE(client.setUp());
+    ASSERT_TRUE(client.setUp(GetParam()));
 
     ASSERT_EQ(OK, trust(untrustedServer, &client));
 
@@ -1715,14 +1734,14 @@
 }
 TEST_P(RpcTransportTest, MaliciousServer) {
     auto [socketType, rpcSecurity, certificateFormat] = GetParam();
-    auto validServer = mServers.emplace_back(std::make_unique<Server>()).get();
-    ASSERT_TRUE(validServer->setUp());
+    auto validServer = std::make_unique<Server>();
+    ASSERT_TRUE(validServer->setUp(GetParam()));
 
-    auto maliciousServer = mServers.emplace_back(std::make_unique<Server>()).get();
-    ASSERT_TRUE(maliciousServer->setUp());
+    auto maliciousServer = std::make_unique<Server>();
+    ASSERT_TRUE(maliciousServer->setUp(GetParam()));
 
     Client client(maliciousServer->getConnectToServerFn());
-    ASSERT_TRUE(client.setUp());
+    ASSERT_TRUE(client.setUp(GetParam()));
 
     ASSERT_EQ(OK, trust(&client, validServer));
     ASSERT_EQ(OK, trust(validServer, &client));
@@ -1738,11 +1757,11 @@
 
 TEST_P(RpcTransportTest, UntrustedClient) {
     auto [socketType, rpcSecurity, certificateFormat] = GetParam();
-    auto server = mServers.emplace_back(std::make_unique<Server>()).get();
-    ASSERT_TRUE(server->setUp());
+    auto server = std::make_unique<Server>();
+    ASSERT_TRUE(server->setUp(GetParam()));
 
     Client client(server->getConnectToServerFn());
-    ASSERT_TRUE(client.setUp());
+    ASSERT_TRUE(client.setUp(GetParam()));
 
     ASSERT_EQ(OK, trust(&client, server));
 
@@ -1757,13 +1776,13 @@
 
 TEST_P(RpcTransportTest, MaliciousClient) {
     auto [socketType, rpcSecurity, certificateFormat] = GetParam();
-    auto server = mServers.emplace_back(std::make_unique<Server>()).get();
-    ASSERT_TRUE(server->setUp());
+    auto server = std::make_unique<Server>();
+    ASSERT_TRUE(server->setUp(GetParam()));
 
     Client validClient(server->getConnectToServerFn());
-    ASSERT_TRUE(validClient.setUp());
+    ASSERT_TRUE(validClient.setUp(GetParam()));
     Client maliciousClient(server->getConnectToServerFn());
-    ASSERT_TRUE(maliciousClient.setUp());
+    ASSERT_TRUE(maliciousClient.setUp(GetParam()));
 
     ASSERT_EQ(OK, trust(&validClient, server));
     ASSERT_EQ(OK, trust(&maliciousClient, server));
@@ -1781,7 +1800,7 @@
     std::condition_variable writeCv;
     bool shouldContinueWriting = false;
     auto serverPostConnect = [&](RpcTransport* serverTransport, FdTrigger* fdTrigger) {
-        std::string message(kMessage);
+        std::string message(RpcTransportTestUtils::kMessage);
         auto status =
                 serverTransport->interruptableWriteFully(fdTrigger, message.data(), message.size());
         if (status != OK) return AssertionFailure() << statusToString(status);
@@ -1794,19 +1813,19 @@
         }
 
         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();
     };
 
-    auto server = mServers.emplace_back(std::make_unique<Server>()).get();
-    ASSERT_TRUE(server->setUp());
+    auto server = std::make_unique<Server>();
+    ASSERT_TRUE(server->setUp(GetParam()));
 
     // Set up client
     Client client(server->getConnectToServerFn());
-    ASSERT_TRUE(client.setUp());
+    ASSERT_TRUE(client.setUp(GetParam()));
 
     // Exchange keys
     ASSERT_EQ(OK, trust(&client, server));
@@ -1819,7 +1838,7 @@
     ASSERT_TRUE(client.setUpTransport());
     // read the first message. This ensures that server has finished handshake and start handling
     // client fd. Server thread should pause at writeCv.wait_for().
-    ASSERT_TRUE(client.readMessage(kMessage));
+    ASSERT_TRUE(client.readMessage(RpcTransportTestUtils::kMessage));
     // Trigger server shutdown after server starts handling client FD. This ensures that the second
     // write is on an FdTrigger that has been shut down.
     server->shutdown();
@@ -1830,7 +1849,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));
 }
@@ -1839,6 +1858,61 @@
                         ::testing::ValuesIn(RpcTransportTest::getRpcTranportTestParams()),
                         RpcTransportTest::PrintParamInfo);
 
+class RpcTransportTlsKeyTest
+      : public testing::TestWithParam<std::tuple<SocketType, RpcCertificateFormat, RpcKeyFormat>> {
+public:
+    template <typename A, typename B>
+    status_t trust(const A& a, const B& b) {
+        auto [socketType, certificateFormat, keyFormat] = GetParam();
+        return RpcTransportTestUtils::trust(RpcSecurity::TLS, certificateFormat, a, b);
+    }
+    static std::string PrintParamInfo(const testing::TestParamInfo<ParamType>& info) {
+        auto [socketType, certificateFormat, keyFormat] = info.param;
+        auto ret = PrintToString(socketType) + "_certificate_" + PrintToString(certificateFormat) +
+                "_key_" + PrintToString(keyFormat);
+        return ret;
+    };
+};
+
+TEST_P(RpcTransportTlsKeyTest, PreSignedCertificate) {
+    auto [socketType, certificateFormat, keyFormat] = GetParam();
+
+    std::vector<uint8_t> pkeyData, certData;
+    {
+        auto pkey = makeKeyPairForSelfSignedCert();
+        ASSERT_NE(nullptr, pkey);
+        auto cert = makeSelfSignedCert(pkey.get(), kCertValidSeconds);
+        ASSERT_NE(nullptr, cert);
+        pkeyData = serializeUnencryptedPrivatekey(pkey.get(), keyFormat);
+        certData = serializeCertificate(cert.get(), certificateFormat);
+    }
+
+    auto desPkey = deserializeUnencryptedPrivatekey(pkeyData, keyFormat);
+    auto desCert = deserializeCertificate(certData, certificateFormat);
+    auto auth = std::make_unique<RpcAuthPreSigned>(std::move(desPkey), std::move(desCert));
+    auto utilsParam =
+            std::make_tuple(socketType, RpcSecurity::TLS, std::make_optional(certificateFormat));
+
+    auto server = std::make_unique<RpcTransportTestUtils::Server>();
+    ASSERT_TRUE(server->setUp(utilsParam, std::move(auth)));
+
+    RpcTransportTestUtils::Client client(server->getConnectToServerFn());
+    ASSERT_TRUE(client.setUp(utilsParam));
+
+    ASSERT_EQ(OK, trust(&client, server));
+    ASSERT_EQ(OK, trust(server, &client));
+
+    server->start();
+    client.run();
+}
+
+INSTANTIATE_TEST_CASE_P(
+        BinderRpc, RpcTransportTlsKeyTest,
+        testing::Combine(testing::ValuesIn(testSocketTypes(false /* hasPreconnected*/)),
+                         testing::Values(RpcCertificateFormat::PEM, RpcCertificateFormat::DER),
+                         testing::Values(RpcKeyFormat::PEM, RpcKeyFormat::DER)),
+        RpcTransportTlsKeyTest::PrintParamInfo);
+
 } // namespace android
 
 int main(int argc, char** argv) {
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/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 3bf6306..3c8289f 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -297,6 +297,20 @@
         return {};
     }
 
+    status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId* displayId) const override {
+        Parcel data, reply;
+        SAFE_PARCEL(data.writeInterfaceToken, ISurfaceComposer::getInterfaceDescriptor());
+        SAFE_PARCEL(remote()->transact, BnSurfaceComposer::GET_PRIMARY_PHYSICAL_DISPLAY_ID, data,
+                    &reply);
+        uint64_t rawId;
+        SAFE_PARCEL(reply.readUint64, &rawId);
+        if (const auto id = DisplayId::fromValue<PhysicalDisplayId>(rawId)) {
+            *displayId = *id;
+            return NO_ERROR;
+        }
+        return NAME_NOT_FOUND;
+    }
+
     sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override {
         Parcel data, reply;
         data.writeInterfaceToken(ISurfaceComposer::getInterfaceDescriptor());
@@ -1738,6 +1752,16 @@
                            [](PhysicalDisplayId id) { return id.value; });
             return reply->writeUint64Vector(rawIds);
         }
+        case GET_PRIMARY_PHYSICAL_DISPLAY_ID: {
+            CHECK_INTERFACE(ISurfaceComposer, data, reply);
+            PhysicalDisplayId id;
+            status_t result = getPrimaryPhysicalDisplayId(&id);
+            if (result != NO_ERROR) {
+                ALOGE("getPrimaryPhysicalDisplayId: Failed to get id");
+                return result;
+            }
+            return reply->writeUint64(id.value);
+        }
         case ADD_REGION_SAMPLING_LISTENER: {
             CHECK_INTERFACE(ISurfaceComposer, data, reply);
             Rect samplingArea;
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 1bca6f9..bbd3cca 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -937,6 +937,10 @@
     return ComposerService::getComposerService()->getPhysicalDisplayIds();
 }
 
+status_t SurfaceComposerClient::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) {
+    return ComposerService::getComposerService()->getPrimaryPhysicalDisplayId(id);
+}
+
 std::optional<PhysicalDisplayId> SurfaceComposerClient::getInternalDisplayId() {
     return ComposerService::getComposerService()->getInternalDisplayId();
 }
@@ -1739,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/ISurfaceComposer.h b/libs/gui/include/gui/ISurfaceComposer.h
index b7cd082..408497d 100644
--- a/libs/gui/include/gui/ISurfaceComposer.h
+++ b/libs/gui/include/gui/ISurfaceComposer.h
@@ -146,6 +146,8 @@
      */
     virtual std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const = 0;
 
+    virtual status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const = 0;
+
     // TODO(b/74619554): Remove this stopgap once the framework is display-agnostic.
     std::optional<PhysicalDisplayId> getInternalDisplayId() const {
         const auto displayIds = getPhysicalDisplayIds();
@@ -630,6 +632,7 @@
         REMOVE_TUNNEL_MODE_ENABLED_LISTENER,
         ADD_WINDOW_INFOS_LISTENER,
         REMOVE_WINDOW_INFOS_LISTENER,
+        GET_PRIMARY_PHYSICAL_DISPLAY_ID,
         // Always append new enum to the end.
     };
 
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 baa6878..403ca0a 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -308,6 +308,7 @@
 
     //! Get stable IDs for connected physical displays
     static std::vector<PhysicalDisplayId> getPhysicalDisplayIds();
+    static status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*);
     static std::optional<PhysicalDisplayId> getInternalDisplayId();
 
     //! Get token for a physical display given its stable ID
@@ -562,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/gui/tests/EndToEndNativeInputTest.cpp b/libs/gui/tests/EndToEndNativeInputTest.cpp
index fc84c1b..78a8b42 100644
--- a/libs/gui/tests/EndToEndNativeInputTest.cpp
+++ b/libs/gui/tests/EndToEndNativeInputTest.cpp
@@ -24,6 +24,7 @@
 
 #include <memory>
 
+#include <android/keycodes.h>
 #include <android/native_window.h>
 
 #include <binder/Binder.h>
@@ -120,8 +121,8 @@
         return std::make_unique<InputSurface>(surfaceControl, width, height);
     }
 
-    InputEvent* consumeEvent() {
-        waitForEventAvailable();
+    InputEvent *consumeEvent(int timeoutMs = 3000) {
+        waitForEventAvailable(timeoutMs);
 
         InputEvent *ev;
         uint32_t seqId;
@@ -178,6 +179,24 @@
         EXPECT_EQ(flags, mev->getFlags() & flags);
     }
 
+    void expectKey(uint32_t keycode) {
+        InputEvent *ev = consumeEvent();
+        ASSERT_NE(ev, nullptr);
+        ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, ev->getType());
+        KeyEvent *keyEvent = static_cast<KeyEvent *>(ev);
+        EXPECT_EQ(AMOTION_EVENT_ACTION_DOWN, keyEvent->getAction());
+        EXPECT_EQ(keycode, keyEvent->getKeyCode());
+        EXPECT_EQ(0, keyEvent->getFlags() & VERIFIED_KEY_EVENT_FLAGS);
+
+        ev = consumeEvent();
+        ASSERT_NE(ev, nullptr);
+        ASSERT_EQ(AINPUT_EVENT_TYPE_KEY, ev->getType());
+        keyEvent = static_cast<KeyEvent *>(ev);
+        EXPECT_EQ(AMOTION_EVENT_ACTION_UP, keyEvent->getAction());
+        EXPECT_EQ(keycode, keyEvent->getKeyCode());
+        EXPECT_EQ(0, keyEvent->getFlags() & VERIFIED_KEY_EVENT_FLAGS);
+    }
+
     virtual ~InputSurface() {
         mInputFlinger->removeInputChannel(mClientChannel->getConnectionToken());
     }
@@ -215,12 +234,12 @@
     }
 
 private:
-    void waitForEventAvailable() {
+    void waitForEventAvailable(int timeoutMs) {
         struct pollfd fd;
 
         fd.fd = mClientChannel->getFd();
         fd.events = POLLIN;
-        poll(&fd, 1, 3000);
+        poll(&fd, 1, timeoutMs);
     }
 
     void populateInputInfo(int width, int height) {
@@ -363,6 +382,14 @@
     }
 }
 
+void injectKey(uint32_t keycode) {
+    char *buf1;
+    asprintf(&buf1, "%d", keycode);
+    if (fork() == 0) {
+        execlp("input", "input", "keyevent", buf1, NULL);
+    }
+}
+
 TEST_F(InputSurfacesTest, can_receive_input) {
     std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
     surface->showAt(100, 100);
@@ -614,6 +641,9 @@
     surface->requestFocus();
 
     surface->assertFocusChange(true);
+
+    injectKey(AKEYCODE_V);
+    surface->expectKey(AKEYCODE_V);
 }
 
 TEST_F(InputSurfacesTest, rotate_surface) {
@@ -781,4 +811,139 @@
     surface->expectTap(1, 1);
 }
 
+TEST_F(InputSurfacesTest, strict_unobscured_input_unobscured_window) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->doTransaction(
+            [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
+    surface->showAt(100, 100);
+
+    injectTap(101, 101);
+
+    EXPECT_NE(surface->consumeEvent(), nullptr);
+    EXPECT_NE(surface->consumeEvent(), nullptr);
+
+    surface->requestFocus();
+    surface->assertFocusChange(true);
+    injectKey(AKEYCODE_V);
+    surface->expectKey(AKEYCODE_V);
+}
+
+TEST_F(InputSurfacesTest, strict_unobscured_input_scaled_without_crop_window) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->doTransaction([&](auto &t, auto &sc) {
+        t.setDropInputMode(sc, gui::DropInputMode::OBSCURED);
+        t.setMatrix(sc, 2.0, 0, 0, 2.0);
+    });
+    surface->showAt(100, 100);
+
+    injectTap(101, 101);
+
+    EXPECT_NE(surface->consumeEvent(), nullptr);
+    EXPECT_NE(surface->consumeEvent(), nullptr);
+
+    surface->requestFocus();
+    surface->assertFocusChange(true);
+    injectKey(AKEYCODE_V);
+    surface->expectKey(AKEYCODE_V);
+}
+
+TEST_F(InputSurfacesTest, strict_unobscured_input_obscured_window) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->mInputInfo.ownerUid = 11111;
+    surface->doTransaction(
+            [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
+    surface->showAt(100, 100);
+    std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100);
+    obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+    obscuringSurface->mInputInfo.ownerUid = 22222;
+    obscuringSurface->showAt(100, 100);
+    injectTap(101, 101);
+    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+
+    surface->requestFocus();
+    surface->assertFocusChange(true);
+    injectKey(AKEYCODE_V);
+    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+}
+
+TEST_F(InputSurfacesTest, strict_unobscured_input_partially_obscured_window) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->mInputInfo.ownerUid = 11111;
+    surface->doTransaction(
+            [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::OBSCURED); });
+    surface->showAt(100, 100);
+    std::unique_ptr<InputSurface> obscuringSurface = makeSurface(100, 100);
+    obscuringSurface->mInputInfo.flags = WindowInfo::Flag::NOT_TOUCHABLE;
+    obscuringSurface->mInputInfo.ownerUid = 22222;
+    obscuringSurface->showAt(190, 190);
+
+    injectTap(101, 101);
+
+    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+
+    surface->requestFocus();
+    surface->assertFocusChange(true);
+    injectKey(AKEYCODE_V);
+    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+}
+
+TEST_F(InputSurfacesTest, strict_unobscured_input_alpha_window) {
+    std::unique_ptr<InputSurface> parentSurface = makeSurface(300, 300);
+    parentSurface->showAt(0, 0, Rect(0, 0, 300, 300));
+
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->showAt(100, 100);
+    surface->doTransaction([&](auto &t, auto &sc) {
+        t.setDropInputMode(sc, gui::DropInputMode::OBSCURED);
+        t.reparent(sc, parentSurface->mSurfaceControl);
+        t.setAlpha(parentSurface->mSurfaceControl, 0.9f);
+    });
+
+    injectTap(101, 101);
+
+    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+
+    surface->requestFocus();
+    surface->assertFocusChange(true);
+    injectKey(AKEYCODE_V);
+    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+}
+
+TEST_F(InputSurfacesTest, strict_unobscured_input_cropped_window) {
+    std::unique_ptr<InputSurface> parentSurface = makeSurface(300, 300);
+    parentSurface->showAt(0, 0, Rect(0, 0, 300, 300));
+
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->doTransaction([&](auto &t, auto &sc) {
+        t.setDropInputMode(sc, gui::DropInputMode::OBSCURED);
+        t.reparent(sc, parentSurface->mSurfaceControl);
+        t.setCrop(parentSurface->mSurfaceControl, Rect(10, 10, 100, 100));
+    });
+    surface->showAt(100, 100);
+
+    injectTap(111, 111);
+
+    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+
+    surface->requestFocus();
+    surface->assertFocusChange(true);
+    injectKey(AKEYCODE_V);
+    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+}
+
+TEST_F(InputSurfacesTest, drop_input_policy) {
+    std::unique_ptr<InputSurface> surface = makeSurface(100, 100);
+    surface->doTransaction(
+            [&](auto &t, auto &sc) { t.setDropInputMode(sc, gui::DropInputMode::ALL); });
+    surface->showAt(100, 100);
+
+    injectTap(101, 101);
+
+    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+
+    surface->requestFocus();
+    surface->assertFocusChange(true);
+    injectKey(AKEYCODE_V);
+    EXPECT_EQ(surface->consumeEvent(100), nullptr);
+}
 } // namespace android::test
diff --git a/libs/gui/tests/Surface_test.cpp b/libs/gui/tests/Surface_test.cpp
index d1ad478..a9f4d09 100644
--- a/libs/gui/tests/Surface_test.cpp
+++ b/libs/gui/tests/Surface_test.cpp
@@ -694,6 +694,7 @@
             bool /*secure*/) override { return nullptr; }
     void destroyDisplay(const sp<IBinder>& /*display */) override {}
     std::vector<PhysicalDisplayId> getPhysicalDisplayIds() const override { return {}; }
+    status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override { return NO_ERROR; }
     sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId) const override { return nullptr; }
     status_t setTransactionState(const FrameTimelineInfo& /*frameTimelineInfo*/,
                                  const Vector<ComposerState>& /*state*/,
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/ui/include_mock/ui/MockFence.h b/libs/ui/include_mock/ui/MockFence.h
new file mode 100644
index 0000000..162ec02
--- /dev/null
+++ b/libs/ui/include_mock/ui/MockFence.h
@@ -0,0 +1,32 @@
+/*
+ * 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 <gmock/gmock.h>
+#include <ui/Fence.h>
+
+namespace android::mock {
+
+class MockFence : public android::Fence {
+public:
+    MockFence() = default;
+    virtual ~MockFence() = default;
+
+    MOCK_METHOD(nsecs_t, getSignalTime, (), (const, override));
+};
+
+}; // 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/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/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..10391a2b 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.
@@ -1912,27 +1913,48 @@
 }
 
 Layer::RoundedCornerState Layer::getRoundedCornerState() const {
-    const auto& p = mDrawingParent.promote();
-    if (p != nullptr) {
-        RoundedCornerState parentState = p->getRoundedCornerState();
-        if (parentState.radius > 0) {
+    // Get parent settings
+    RoundedCornerState parentSettings;
+    const auto& parent = mDrawingParent.promote();
+    if (parent != nullptr) {
+        parentSettings = parent->getRoundedCornerState();
+        if (parentSettings.radius > 0) {
             ui::Transform t = getActiveTransform(getDrawingState());
             t = t.inverse();
-            parentState.cropRect = t.transform(parentState.cropRect);
+            parentSettings.cropRect = t.transform(parentSettings.cropRect);
             // The rounded corners shader only accepts 1 corner radius for performance reasons,
             // but a transform matrix can define horizontal and vertical scales.
             // Let's take the average between both of them and pass into the shader, practically we
             // never do this type of transformation on windows anyway.
             auto scaleX = sqrtf(t[0][0] * t[0][0] + t[0][1] * t[0][1]);
             auto scaleY = sqrtf(t[1][0] * t[1][0] + t[1][1] * t[1][1]);
-            parentState.radius *= (scaleX + scaleY) / 2.0f;
-            return parentState;
+            parentSettings.radius *= (scaleX + scaleY) / 2.0f;
         }
     }
+
+    // Get layer settings
+    Rect layerCropRect = getCroppedBufferSize(getDrawingState());
     const float radius = getDrawingState().cornerRadius;
-    return radius > 0 && getCroppedBufferSize(getDrawingState()).isValid()
-            ? RoundedCornerState(getCroppedBufferSize(getDrawingState()).toFloatRect(), radius)
-            : RoundedCornerState();
+    RoundedCornerState layerSettings(layerCropRect.toFloatRect(), radius);
+
+    if (layerSettings.radius > 0 && parentSettings.radius > 0) {
+        // If the parent and the layer have rounded corner settings, use the parent settings if the
+        // parent crop is entirely inside the layer crop.
+        // This has limitations and cause rendering artifacts. See b/200300845 for correct fix.
+        if (parentSettings.cropRect.left > layerCropRect.left &&
+            parentSettings.cropRect.top > layerCropRect.top &&
+            parentSettings.cropRect.right < layerCropRect.right &&
+            parentSettings.cropRect.bottom < layerCropRect.bottom) {
+            return parentSettings;
+        } else {
+            return layerSettings;
+        }
+    } else if (layerSettings.radius > 0) {
+        return layerSettings;
+    } else if (parentSettings.radius > 0) {
+        return parentSettings;
+    }
+    return {};
 }
 
 void Layer::prepareShadowClientComposition(LayerFE::LayerSettings& caster,
@@ -2266,6 +2288,74 @@
     }
 }
 
+gui::DropInputMode Layer::getDropInputMode() const {
+    gui::DropInputMode mode = mDrawingState.dropInputMode;
+    if (mode == gui::DropInputMode::ALL) {
+        return mode;
+    }
+    sp<Layer> parent = mDrawingParent.promote();
+    if (parent) {
+        gui::DropInputMode parentMode = parent->getDropInputMode();
+        if (parentMode != gui::DropInputMode::NONE) {
+            return parentMode;
+        }
+    }
+    return mode;
+}
+
+void Layer::handleDropInputMode(gui::WindowInfo& info) const {
+    if (mDrawingState.inputInfo.inputFeatures.test(WindowInfo::Feature::NO_INPUT_CHANNEL)) {
+        return;
+    }
+
+    // Check if we need to drop input unconditionally
+    gui::DropInputMode dropInputMode = getDropInputMode();
+    if (dropInputMode == gui::DropInputMode::ALL) {
+        info.inputFeatures |= WindowInfo::Feature::DROP_INPUT;
+        ALOGV("Dropping input for %s as requested by policy.", getDebugName());
+        return;
+    }
+
+    // Check if we need to check if the window is obscured by parent
+    if (dropInputMode != gui::DropInputMode::OBSCURED) {
+        return;
+    }
+
+    // Check if the parent has set an alpha on the layer
+    sp<Layer> parent = mDrawingParent.promote();
+    if (parent && parent->getAlpha() != 1.0_hf) {
+        info.inputFeatures |= WindowInfo::Feature::DROP_INPUT;
+        ALOGV("Dropping input for %s as requested by policy because alpha=%f", getDebugName(),
+              static_cast<float>(getAlpha()));
+    }
+
+    // Check if the parent has cropped the buffer
+    Rect bufferSize = getCroppedBufferSize(getDrawingState());
+    if (!bufferSize.isValid()) {
+        info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED;
+        return;
+    }
+
+    // Screenbounds are the layer bounds cropped by parents, transformed to screenspace.
+    // To check if the layer has been cropped, we take the buffer bounds, apply the local
+    // layer crop and apply the same set of transforms to move to screenspace. If the bounds
+    // match then the layer has not been cropped by its parents.
+    Rect bufferInScreenSpace(getTransform().transform(bufferSize));
+    bool croppedByParent = bufferInScreenSpace != Rect{mScreenBounds};
+
+    if (croppedByParent) {
+        info.inputFeatures |= WindowInfo::Feature::DROP_INPUT;
+        ALOGV("Dropping input for %s as requested by policy because buffer is cropped by parent",
+              getDebugName());
+    } else {
+        // If the layer is not obscured by its parents (by setting an alpha or crop), then only drop
+        // input if the window is obscured. This check should be done in surfaceflinger but the
+        // logic currently resides in inputflinger. So pass the if_obscured check to input to only
+        // drop input events if the window is obscured.
+        info.inputFeatures |= WindowInfo::Feature::DROP_INPUT_IF_OBSCURED;
+    }
+}
+
 WindowInfo Layer::fillInputInfo(const ui::Transform& displayTransform) {
     if (!hasInputInfo()) {
         mDrawingState.inputInfo.name = getName();
@@ -2293,6 +2383,7 @@
     info.visible = hasInputInfo() ? canReceiveInput() : isVisible();
     info.alpha = getAlpha();
     fillTouchOcclusionMode(info);
+    handleDropInputMode(info);
 
     auto cropLayer = mDrawingState.touchableRegionCrop.promote();
     if (info.replaceTouchableRegionWithCrop) {
@@ -2541,6 +2632,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..7b9303f 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;
@@ -601,10 +606,8 @@
     virtual bool getTransformToDisplayInverse() const { return false; }
 
     // Returns how rounded corners should be drawn for this layer.
-    // This will traverse the hierarchy until it reaches its root, finding topmost rounded
-    // corner definition and converting it into current layer's coordinates.
-    // As of now, only 1 corner radius per display list is supported. Subsequent ones will be
-    // ignored.
+    // A layer can override its parent's rounded corner settings if the parent's rounded
+    // corner crop does not intersect with its own rounded corner crop.
     virtual RoundedCornerState getRoundedCornerState() const;
 
     bool hasRoundedCorners() const override { return getRoundedCornerState().radius > .0f; }
@@ -1060,6 +1063,8 @@
     bool setFrameRateForLayerTree(FrameRate);
     void setZOrderRelativeOf(const wp<Layer>& relativeOf);
     bool isTrustedOverlay() const;
+    gui::DropInputMode getDropInputMode() const;
+    void handleDropInputMode(gui::WindowInfo& info) const;
 
     // Find the root of the cloned hierarchy, this means the first non cloned parent.
     // This will return null if first non cloned parent is not found.
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 8dbb8b7..da2204e 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -639,6 +639,12 @@
     return displayIds;
 }
 
+status_t SurfaceFlinger::getPrimaryPhysicalDisplayId(PhysicalDisplayId* id) const {
+    Mutex::Autolock lock(mStateLock);
+    *id = getInternalDisplayIdLocked();
+    return NO_ERROR;
+}
+
 sp<IBinder> SurfaceFlinger::getPhysicalDisplayToken(PhysicalDisplayId displayId) const {
     Mutex::Autolock lock(mStateLock);
     return getPhysicalDisplayTokenLocked(displayId);
@@ -1710,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);
@@ -4147,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
@@ -5244,6 +5268,7 @@
         case REMOVE_TUNNEL_MODE_ENABLED_LISTENER:
         case NOTIFY_POWER_BOOST:
         case SET_GLOBAL_SHADOW_SETTINGS:
+        case GET_PRIMARY_PHYSICAL_DISPLAY_ID:
         case ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN: {
             // ACQUIRE_FRAME_RATE_FLEXIBILITY_TOKEN and OVERRIDE_HDR_TYPES are used by CTS tests,
             // which acquire the necessary permission dynamically. Don't use the permission cache
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 6adad6d..141d7ac 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -615,6 +615,8 @@
         Mutex::Autolock lock(mStateLock);
         return getPhysicalDisplayIdsLocked();
     }
+    status_t getPrimaryPhysicalDisplayId(PhysicalDisplayId*) const override EXCLUDES(mStateLock);
+
     sp<IBinder> getPhysicalDisplayToken(PhysicalDisplayId displayId) const override;
     status_t setTransactionState(const FrameTimelineInfo& frameTimelineInfo,
                                  const Vector<ComposerState>& state,
diff --git a/services/surfaceflinger/SurfaceFlingerProperties.cpp b/services/surfaceflinger/SurfaceFlingerProperties.cpp
index 4a69c8f..e15eae8 100644
--- a/services/surfaceflinger/SurfaceFlingerProperties.cpp
+++ b/services/surfaceflinger/SurfaceFlingerProperties.cpp
@@ -34,6 +34,8 @@
 using android::hardware::graphics::common::V1_2::PixelFormat;
 using android::ui::DisplayPrimaries;
 
+// Keep logic in sync with WindowManagerService functions that query SurfaceFlinger properties.
+// Consider exposing properties via ISurfaceComposer instead.
 int64_t vsync_event_phase_offset_ns(int64_t defaultValue) {
     auto temp = SurfaceFlingerProperties::vsync_event_phase_offset_ns();
     if (temp.has_value()) {
diff --git a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
index 4076253..e5872c1 100644
--- a/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
+++ b/services/surfaceflinger/tests/LayerTypeAndRenderTypeTransaction_test.cpp
@@ -465,6 +465,95 @@
     }
 }
 
+TEST_P(LayerTypeAndRenderTypeTransactionTest, ChildCornerRadiusTakesPrecedence) {
+    sp<SurfaceControl> parent;
+    sp<SurfaceControl> child;
+    const uint32_t size = 64;
+    const uint32_t parentSize = size * 3;
+    const uint32_t testLength = 4;
+    const float cornerRadius = 20.0f;
+    ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, parentSize, parentSize));
+    ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size));
+
+    Transaction()
+            .setCornerRadius(parent, cornerRadius)
+            .setCornerRadius(child, cornerRadius)
+            .reparent(child, parent)
+            .setPosition(child, size, size)
+            .apply();
+
+    {
+        const uint32_t top = size - 1;
+        const uint32_t left = size - 1;
+        const uint32_t bottom = size * 2 - 1;
+        const uint32_t right = size * 2 - 1;
+        auto shot = getScreenCapture();
+        // Edges are transparent
+        // TL
+        shot->expectColor(Rect(left, top, testLength, testLength), Color::RED);
+        // TR
+        shot->expectColor(Rect(right - testLength, top, right, testLength), Color::RED);
+        // BL
+        shot->expectColor(Rect(left, bottom - testLength, testLength, bottom - testLength),
+                          Color::RED);
+        // BR
+        shot->expectColor(Rect(right - testLength, bottom - testLength, right, bottom), Color::RED);
+        // Solid center
+        shot->expectColor(Rect(parentSize / 2 - testLength / 2, parentSize / 2 - testLength / 2,
+                               parentSize / 2 + testLength / 2, parentSize / 2 + testLength / 2),
+                          Color::GREEN);
+    }
+}
+
+// Test if ParentCornerRadiusTakesPrecedence if the parent corner radius crop is fully contained by
+// the child corner radius crop.
+TEST_P(LayerTypeAndRenderTypeTransactionTest, ParentCornerRadiusTakesPrecedence) {
+    sp<SurfaceControl> parent;
+    sp<SurfaceControl> child;
+    const uint32_t size = 64;
+    const uint32_t parentSize = size * 3;
+    const Rect parentCrop(size + 1, size + 1, size * 2 - 1, size * 2 - 1);
+    const uint32_t testLength = 4;
+    const float cornerRadius = 20.0f;
+    ASSERT_NO_FATAL_FAILURE(parent = createLayer("parent", parentSize, parentSize));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(parent, Color::RED, parentSize, parentSize));
+    ASSERT_NO_FATAL_FAILURE(child = createLayer("child", size, size));
+    ASSERT_NO_FATAL_FAILURE(fillLayerColor(child, Color::GREEN, size, size));
+
+    Transaction()
+            .setCornerRadius(parent, cornerRadius)
+            .setCrop(parent, parentCrop)
+            .setCornerRadius(child, cornerRadius)
+            .reparent(child, parent)
+            .setPosition(child, size, size)
+            .apply();
+
+    {
+        const uint32_t top = size - 1;
+        const uint32_t left = size - 1;
+        const uint32_t bottom = size * 2 - 1;
+        const uint32_t right = size * 2 - 1;
+        auto shot = getScreenCapture();
+        // Edges are transparent
+        // TL
+        shot->expectColor(Rect(left, top, testLength, testLength), Color::BLACK);
+        // TR
+        shot->expectColor(Rect(right - testLength, top, right, testLength), Color::BLACK);
+        // BL
+        shot->expectColor(Rect(left, bottom - testLength, testLength, bottom - testLength),
+                          Color::BLACK);
+        // BR
+        shot->expectColor(Rect(right - testLength, bottom - testLength, right, bottom),
+                          Color::BLACK);
+        // Solid center
+        shot->expectColor(Rect(parentSize / 2 - testLength / 2, parentSize / 2 - testLength / 2,
+                               parentSize / 2 + testLength / 2, parentSize / 2 + testLength / 2),
+                          Color::GREEN);
+    }
+}
+
 TEST_P(LayerTypeAndRenderTypeTransactionTest, SetBackgroundBlurRadiusSimple) {
     if (!deviceSupportsBlurs()) GTEST_SKIP();
     if (!deviceUsesSkiaRenderEngine()) GTEST_SKIP();
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);