Merge "Don't depend on private/android_filesystem_config.h" into main
diff --git a/.gitignore b/.gitignore
index ed653c6..1ad8a24 100644
--- a/.gitignore
+++ b/.gitignore
@@ -3,3 +3,6 @@
 .idea/
 .vscode/
 *.code-workspace
+
+# Rust artifacts
+**/target/
diff --git a/include/android/sharedmem.h b/include/android/sharedmem.h
index 645fa8a..1d513a6 100644
--- a/include/android/sharedmem.h
+++ b/include/android/sharedmem.h
@@ -53,27 +53,27 @@
 /**
  * Create a shared memory region.
  *
- * Create shared memory region and returns a file descriptor.  The resulting file descriptor can be
- * mmap'ed to process memory space with PROT_READ | PROT_WRITE | PROT_EXEC. Access to shared memory
- * region can be restricted with {@link ASharedMemory_setProt}.
+ * Create a shared memory region and returns a file descriptor.  The resulting file descriptor can be
+ * mapped into the process' memory using mmap(2) with `PROT_READ | PROT_WRITE | PROT_EXEC`.
+ * Access to shared memory regions can be restricted with {@link ASharedMemory_setProt}.
  *
- * Use close() to release the shared memory region.
+ * Use close(2) to release the shared memory region.
  *
  * Use <a href="/reference/android/os/ParcelFileDescriptor">android.os.ParcelFileDescriptor</a>
  * to pass the file descriptor to another process. File descriptors may also be sent to other
- * processes over a Unix domain socket with sendmsg and SCM_RIGHTS. See sendmsg(3) and
+ * processes over a Unix domain socket with sendmsg(2) and `SCM_RIGHTS`. See sendmsg(3) and
  * cmsg(3) man pages for more information.
  *
  * If you intend to share this file descriptor with a child process after
- * calling exec(3), note that you will need to use fcntl(2) with F_SETFD
- * to clear the FD_CLOEXEC flag for this to work on all versions of Android.
+ * calling exec(3), note that you will need to use fcntl(2) with `F_SETFD`
+ * to clear the `FD_CLOEXEC` flag for this to work on all versions of Android.
  *
  * Available since API level 26.
  *
  * \param name an optional name.
  * \param size size of the shared memory region
  * \return file descriptor that denotes the shared memory;
- *         -1 and sets errno on failure, or -EINVAL if the error is that size was 0.
+ *         -1 and sets `errno` on failure, or `-EINVAL` if the error is that size was 0.
  */
 int ASharedMemory_create(const char *name, size_t size) __INTRODUCED_IN(26);
 
@@ -83,7 +83,7 @@
  * Available since API level 26.
  *
  * \param fd file descriptor of the shared memory region
- * \return size in bytes; 0 if fd is not a valid shared memory file descriptor.
+ * \return size in bytes; 0 if `fd` is not a valid shared memory file descriptor.
  */
 size_t ASharedMemory_getSize(int fd) __INTRODUCED_IN(26);
 
@@ -115,9 +115,9 @@
  * Available since API level 26.
  *
  * \param fd   file descriptor of the shared memory region.
- * \param prot any bitwise-or'ed combination of PROT_READ, PROT_WRITE, PROT_EXEC denoting
+ * \param prot any bitwise-or'ed combination of `PROT_READ`, `PROT_WRITE`, `PROT_EXEC` denoting
  *             updated access. Note access can only be removed, but not added back.
- * \return 0 for success, -1 and sets errno on failure.
+ * \return 0 for success, -1 and sets `errno` on failure.
  */
 int ASharedMemory_setProt(int fd, int prot) __INTRODUCED_IN(26);
 
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index b0c1af2..3bc4f92 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -53,6 +53,11 @@
 // Another arbitrary value a binder count needs to drop below before another callback will be called
 uint32_t BpBinder::sBinderProxyCountLowWatermark = 2000;
 
+std::atomic<uint32_t> BpBinder::sBinderProxyCount(0);
+std::atomic<uint32_t> BpBinder::sBinderProxyCountWarned(0);
+
+static constexpr uint32_t kBinderProxyCountWarnInterval = 5000;
+
 // Log any transactions for which the data exceeds this size
 #define LOG_TRANSACTIONS_OVER_SIZE (300 * 1024)
 
@@ -192,6 +197,18 @@
         }
         sTrackingMap[trackedUid]++;
     }
+    uint32_t numProxies = sBinderProxyCount.fetch_add(1, std::memory_order_relaxed);
+    uint32_t numLastWarned = sBinderProxyCountWarned.load(std::memory_order_relaxed);
+    uint32_t numNextWarn = numLastWarned + kBinderProxyCountWarnInterval;
+    if (numProxies >= numNextWarn) {
+        // Multiple threads can get here, make sure only one of them gets to
+        // update the warn counter.
+        if (sBinderProxyCountWarned.compare_exchange_strong(numLastWarned,
+                                                            numNextWarn,
+                                                            std::memory_order_relaxed)) {
+            ALOGW("Unexpectedly many live BinderProxies: %d\n", numProxies);
+        }
+    }
     return sp<BpBinder>::make(BinderHandle{handle}, trackedUid);
 }
 
@@ -604,6 +621,7 @@
             }
         }
     }
+    --sBinderProxyCount;
 
     if (ipc) {
         ipc->expungeHandle(binderHandle(), this);
@@ -692,6 +710,11 @@
     return 0;
 }
 
+uint32_t BpBinder::getBinderProxyCount()
+{
+    return sBinderProxyCount.load();
+}
+
 void BpBinder::getCountByUid(Vector<uint32_t>& uids, Vector<uint32_t>& counts)
 {
     AutoMutex _l(sTrackingLock);
diff --git a/libs/binder/include/binder/BpBinder.h b/libs/binder/include/binder/BpBinder.h
index fc8089d..28fb9f1 100644
--- a/libs/binder/include/binder/BpBinder.h
+++ b/libs/binder/include/binder/BpBinder.h
@@ -88,6 +88,7 @@
     static void         setCountByUidEnabled(bool enable);
     static void         setLimitCallback(binder_proxy_limit_callback cb);
     static void         setBinderProxyCountWatermarks(int high, int low);
+    static uint32_t     getBinderProxyCount();
 
     std::optional<int32_t> getDebugBinderHandle() const;
 
@@ -209,6 +210,8 @@
     static uint32_t                             sBinderProxyCountLowWatermark;
     static bool                                 sBinderProxyThrottleCreate;
     static std::unordered_map<int32_t,uint32_t> sLastLimitCallbackMap;
+    static std::atomic<uint32_t>                sBinderProxyCount;
+    static std::atomic<uint32_t>                sBinderProxyCountWarned;
 };
 
 } // namespace android
diff --git a/libs/binder/servicedispatcher.cpp b/libs/binder/servicedispatcher.cpp
index 692cc95..8e95d69 100644
--- a/libs/binder/servicedispatcher.cpp
+++ b/libs/binder/servicedispatcher.cpp
@@ -59,12 +59,13 @@
     auto basename = Basename(program);
     auto format = R"(dispatch calls to RPC service.
 Usage:
-  %s [-g] <service_name>
+  %s [-g] [-i <ip_address>] <service_name>
     <service_name>: the service to connect to.
   %s [-g] manager
     Runs an RPC-friendly service that redirects calls to servicemanager.
 
   -g: use getService() instead of checkService().
+  -i: use ip_address when setting up the server instead of '127.0.0.1'
 
   If successful, writes port number and a new line character to stdout, and
   blocks until killed.
@@ -74,7 +75,8 @@
     return EX_USAGE;
 }
 
-int Dispatch(const char* name, const ServiceRetriever& serviceRetriever) {
+int Dispatch(const char* name, const ServiceRetriever& serviceRetriever,
+             const char* ip_address = kLocalInetAddress) {
     auto sm = defaultServiceManager();
     if (nullptr == sm) {
         LOG(ERROR) << "No servicemanager";
@@ -91,7 +93,7 @@
         return EX_SOFTWARE;
     }
     unsigned int port;
-    if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) {
+    if (status_t status = rpcServer->setupInetServer(ip_address, 0, &port); status != OK) {
         LOG(ERROR) << "setupInetServer failed: " << statusToString(status);
         return EX_SOFTWARE;
     }
@@ -188,7 +190,8 @@
 // Workaround for b/191059588.
 // TODO(b/191059588): Once we can run RpcServer on single-threaded services,
 //   `servicedispatcher manager` should call Dispatch("manager") directly.
-int wrapServiceManager(const ServiceRetriever& serviceRetriever) {
+int wrapServiceManager(const ServiceRetriever& serviceRetriever,
+                       const char* ip_address = kLocalInetAddress) {
     auto sm = defaultServiceManager();
     if (nullptr == sm) {
         LOG(ERROR) << "No servicemanager";
@@ -212,7 +215,7 @@
     auto rpcServer = RpcServer::make();
     rpcServer->setRootObject(service);
     unsigned int port;
-    if (status_t status = rpcServer->setupInetServer(kLocalInetAddress, 0, &port); status != OK) {
+    if (status_t status = rpcServer->setupInetServer(ip_address, 0, &port); status != OK) {
         LOG(ERROR) << "Unable to set up inet server: " << statusToString(status);
         return EX_SOFTWARE;
     }
@@ -272,11 +275,15 @@
 
     int opt;
     ServiceRetriever serviceRetriever = &android::IServiceManager::checkService;
-    while (-1 != (opt = getopt(argc, argv, "g"))) {
+    char* ip_address = nullptr;
+    while (-1 != (opt = getopt(argc, argv, "gi:"))) {
         switch (opt) {
             case 'g': {
                 serviceRetriever = &android::IServiceManager::getService;
             } break;
+            case 'i': {
+                ip_address = optarg;
+            } break;
             default: {
                 return Usage(argv[0]);
             }
@@ -291,7 +298,15 @@
     auto name = argv[optind];
 
     if (name == "manager"sv) {
-        return wrapServiceManager(serviceRetriever);
+        if (ip_address) {
+            return wrapServiceManager(serviceRetriever, ip_address);
+        } else {
+            return wrapServiceManager(serviceRetriever);
+        }
     }
-    return Dispatch(name, serviceRetriever);
+    if (ip_address) {
+        return Dispatch(name, serviceRetriever, ip_address);
+    } else {
+        return Dispatch(name, serviceRetriever);
+    }
 }
diff --git a/libs/binder/tests/binderLibTest.cpp b/libs/binder/tests/binderLibTest.cpp
index e021af0..0396869 100644
--- a/libs/binder/tests/binderLibTest.cpp
+++ b/libs/binder/tests/binderLibTest.cpp
@@ -1441,6 +1441,36 @@
     EXPECT_GE(epochMsAfter, epochMsBefore + delay);
 }
 
+TEST_F(BinderLibTest, BinderProxyCount) {
+    Parcel data, reply;
+    sp<IBinder> server = addServer();
+    ASSERT_NE(server, nullptr);
+
+    uint32_t initialCount = BpBinder::getBinderProxyCount();
+    size_t iterations = 100;
+    {
+        uint32_t count = initialCount;
+        std::vector<sp<IBinder> > proxies;
+        sp<IBinder> proxy;
+        // Create binder proxies and verify the count.
+        for (size_t i = 0; i < iterations; i++) {
+            ASSERT_THAT(server->transact(BINDER_LIB_TEST_CREATE_BINDER_TRANSACTION, data, &reply),
+                        StatusEq(NO_ERROR));
+            proxies.push_back(reply.readStrongBinder());
+            EXPECT_EQ(BpBinder::getBinderProxyCount(), ++count);
+        }
+        // Remove every other one and verify the count.
+        auto it = proxies.begin();
+        for (size_t i = 0; it != proxies.end(); i++) {
+            if (i % 2 == 0) {
+                it = proxies.erase(it);
+                EXPECT_EQ(BpBinder::getBinderProxyCount(), --count);
+            }
+        }
+    }
+    EXPECT_EQ(BpBinder::getBinderProxyCount(), initialCount);
+}
+
 class BinderLibRpcTestBase : public BinderLibTest {
 public:
     void SetUp() override {
diff --git a/libs/binder/trusty/fuzzer/Android.bp b/libs/binder/trusty/fuzzer/Android.bp
index 2f1f54b..4f9b5c4 100644
--- a/libs/binder/trusty/fuzzer/Android.bp
+++ b/libs/binder/trusty/fuzzer/Android.bp
@@ -24,6 +24,7 @@
         "-DTRUSTY_APP_PORT=\"com.android.trusty.binder.test.service\"",
         "-DTRUSTY_APP_UUID=\"d42f06c5-9dc5-455b-9914-cf094116cfa8\"",
         "-DTRUSTY_APP_FILENAME=\"binder-test-service.syms.elf\"",
+        "-DTRUSTY_APP_MAX_CONNECTIONS=1",
     ],
 }
 
@@ -35,5 +36,30 @@
         "-DTRUSTY_APP_PORT=\"com.android.trusty.binderRpcTestService.V0\"",
         "-DTRUSTY_APP_UUID=\"87e424e5-69d7-4bbd-8b7c-7e24812cbc94\"",
         "-DTRUSTY_APP_FILENAME=\"binderRpcTestService.syms.elf\"",
+        "-DTRUSTY_APP_MAX_CONNECTIONS=1",
+    ],
+}
+
+cc_fuzz {
+    name: "trusty_binder_fuzzer_multi_connection",
+    defaults: ["trusty_fuzzer_defaults"],
+    srcs: [":trusty_tipc_fuzzer"],
+    cflags: [
+        "-DTRUSTY_APP_PORT=\"com.android.trusty.binder.test.service\"",
+        "-DTRUSTY_APP_UUID=\"d42f06c5-9dc5-455b-9914-cf094116cfa8\"",
+        "-DTRUSTY_APP_FILENAME=\"binder-test-service.syms.elf\"",
+        "-DTRUSTY_APP_MAX_CONNECTIONS=10",
+    ],
+}
+
+cc_fuzz {
+    name: "trusty_binder_rpc_fuzzer_multi_connection",
+    defaults: ["trusty_fuzzer_defaults"],
+    srcs: [":trusty_tipc_fuzzer"],
+    cflags: [
+        "-DTRUSTY_APP_PORT=\"com.android.trusty.binderRpcTestService.V0\"",
+        "-DTRUSTY_APP_UUID=\"87e424e5-69d7-4bbd-8b7c-7e24812cbc94\"",
+        "-DTRUSTY_APP_FILENAME=\"binderRpcTestService.syms.elf\"",
+        "-DTRUSTY_APP_MAX_CONNECTIONS=10",
     ],
 }
diff --git a/libs/nativewindow/TEST_MAPPING b/libs/nativewindow/TEST_MAPPING
index 3d7f3c2..bbad757 100644
--- a/libs/nativewindow/TEST_MAPPING
+++ b/libs/nativewindow/TEST_MAPPING
@@ -3,5 +3,13 @@
     {
       "name": "libnativewindow_test"
     }
+  ],
+  "postsubmit": [
+    {
+      "name": "libnativewindow_bindgen_test"
+    },
+    {
+      "name": "libnativewindow_rs-internal_test"
+    }
   ]
 }
diff --git a/libs/nativewindow/include/android/data_space.h b/libs/nativewindow/include/android/data_space.h
index 47a4bfc..eab21fb 100644
--- a/libs/nativewindow/include/android/data_space.h
+++ b/libs/nativewindow/include/android/data_space.h
@@ -81,11 +81,12 @@
     STANDARD_UNSPECIFIED = 0 << 16,
 
     /**
+     * <pre>
      * Primaries:       x       y
      *  green           0.300   0.600
      *  blue            0.150   0.060
      *  red             0.640   0.330
-     *  white (D65)     0.3127  0.3290
+     *  white (D65)     0.3127  0.3290</pre>
      *
      * Use the unadjusted KR = 0.2126, KB = 0.0722 luminance interpretation
      * for RGB conversion.
@@ -93,11 +94,12 @@
     STANDARD_BT709 = 1 << 16,
 
     /**
+     * <pre>
      * Primaries:       x       y
      *  green           0.290   0.600
      *  blue            0.150   0.060
      *  red             0.640   0.330
-     *  white (D65)     0.3127  0.3290
+     *  white (D65)     0.3127  0.3290</pre>
      *
      *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
      *  for RGB conversion from the one purely determined by the primaries
@@ -107,11 +109,12 @@
     STANDARD_BT601_625 = 2 << 16,
 
     /**
+     * <pre>
      * Primaries:       x       y
      *  green           0.290   0.600
      *  blue            0.150   0.060
      *  red             0.640   0.330
-     *  white (D65)     0.3127  0.3290
+     *  white (D65)     0.3127  0.3290</pre>
      *
      * Use the unadjusted KR = 0.222, KB = 0.071 luminance interpretation
      * for RGB conversion.
@@ -119,11 +122,12 @@
     STANDARD_BT601_625_UNADJUSTED = 3 << 16,
 
     /**
+     * <pre>
      * Primaries:       x       y
      *  green           0.310   0.595
      *  blue            0.155   0.070
      *  red             0.630   0.340
-     *  white (D65)     0.3127  0.3290
+     *  white (D65)     0.3127  0.3290</pre>
      *
      *  KR = 0.299, KB = 0.114. This adjusts the luminance interpretation
      *  for RGB conversion from the one purely determined by the primaries
@@ -133,11 +137,12 @@
     STANDARD_BT601_525 = 4 << 16,
 
     /**
+     * <pre>
      * Primaries:       x       y
      *  green           0.310   0.595
      *  blue            0.155   0.070
      *  red             0.630   0.340
-     *  white (D65)     0.3127  0.3290
+     *  white (D65)     0.3127  0.3290</pre>
      *
      * Use the unadjusted KR = 0.212, KB = 0.087 luminance interpretation
      * for RGB conversion (as in SMPTE 240M).
@@ -145,11 +150,12 @@
     STANDARD_BT601_525_UNADJUSTED = 5 << 16,
 
     /**
+     * <pre>
      * Primaries:       x       y
      *  green           0.170   0.797
      *  blue            0.131   0.046
      *  red             0.708   0.292
-     *  white (D65)     0.3127  0.3290
+     *  white (D65)     0.3127  0.3290</pre>
      *
      * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
      * for RGB conversion.
@@ -157,11 +163,12 @@
     STANDARD_BT2020 = 6 << 16,
 
     /**
+     * <pre>
      * Primaries:       x       y
      *  green           0.170   0.797
      *  blue            0.131   0.046
      *  red             0.708   0.292
-     *  white (D65)     0.3127  0.3290
+     *  white (D65)     0.3127  0.3290</pre>
      *
      * Use the unadjusted KR = 0.2627, KB = 0.0593 luminance interpretation
      * for RGB conversion using the linear domain.
@@ -169,11 +176,12 @@
     STANDARD_BT2020_CONSTANT_LUMINANCE = 7 << 16,
 
     /**
+     * <pre>
      * Primaries:       x      y
      *  green           0.21   0.71
      *  blue            0.14   0.08
      *  red             0.67   0.33
-     *  white (C)       0.310  0.316
+     *  white (C)       0.310  0.316</pre>
      *
      * Use the unadjusted KR = 0.30, KB = 0.11 luminance interpretation
      * for RGB conversion.
@@ -181,11 +189,12 @@
     STANDARD_BT470M = 8 << 16,
 
     /**
+     * <pre>
      * Primaries:       x       y
      *  green           0.243   0.692
      *  blue            0.145   0.049
      *  red             0.681   0.319
-     *  white (C)       0.310   0.316
+     *  white (C)       0.310   0.316</pre>
      *
      * Use the unadjusted KR = 0.254, KB = 0.068 luminance interpretation
      * for RGB conversion.
@@ -194,21 +203,23 @@
 
     /**
      * SMPTE EG 432-1 and SMPTE RP 431-2. (DCI-P3)
+     * <pre>
      * Primaries:       x       y
      *  green           0.265   0.690
      *  blue            0.150   0.060
      *  red             0.680   0.320
-     *  white (D65)     0.3127  0.3290
+     *  white (D65)     0.3127  0.3290</pre>
      */
     STANDARD_DCI_P3 = 10 << 16,
 
     /**
      * Adobe RGB
+     * <pre>
      * Primaries:       x       y
      *  green           0.210   0.710
      *  blue            0.150   0.060
      *  red             0.640   0.330
-     *  white (D65)     0.3127  0.3290
+     *  white (D65)     0.3127  0.3290</pre>
      */
     STANDARD_ADOBE_RGB = 11 << 16,
 
@@ -242,83 +253,86 @@
     TRANSFER_UNSPECIFIED = 0 << 22,
 
     /**
+     * Linear transfer.
+     * <pre>
      * Transfer characteristic curve:
-     *  E = L
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
+     * E = L
+     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *     E - corresponding electrical signal</pre>
      */
     TRANSFER_LINEAR = 1 << 22,
 
     /**
+     * sRGB transfer.
+     * <pre>
      * Transfer characteristic curve:
-     *
      * E = 1.055 * L^(1/2.4) - 0.055  for 0.0031308 <= L <= 1
      *   = 12.92 * L                  for 0 <= L < 0.0031308
      *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *     E - corresponding electrical signal
+     *     E - corresponding electrical signal</pre>
      */
     TRANSFER_SRGB = 2 << 22,
 
     /**
-     * BT.601 525, BT.601 625, BT.709, BT.2020
-     *
+     * SMPTE 170M transfer.
+     * <pre>
      * Transfer characteristic curve:
-     *  E = 1.099 * L ^ 0.45 - 0.099  for 0.018 <= L <= 1
-     *    = 4.500 * L                 for 0 <= L < 0.018
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
+     * E = 1.099 * L ^ 0.45 - 0.099  for 0.018 <= L <= 1
+     *   = 4.500 * L                 for 0 <= L < 0.018
+     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *     E - corresponding electrical signal</pre>
      */
     TRANSFER_SMPTE_170M = 3 << 22,
 
     /**
-     * Assumed display gamma 2.2.
-     *
+     * Display gamma 2.2.
+     * <pre>
      * Transfer characteristic curve:
-     *  E = L ^ (1/2.2)
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
+     * E = L ^ (1/2.2)
+     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *     E - corresponding electrical signal</pre>
      */
     TRANSFER_GAMMA2_2 = 4 << 22,
 
     /**
-     *  display gamma 2.6.
-     *
+     * Display gamma 2.6.
+     * <pre>
      * Transfer characteristic curve:
-     *  E = L ^ (1/2.6)
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
+     * E = L ^ (1/2.6)
+     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *     E - corresponding electrical signal</pre>
      */
     TRANSFER_GAMMA2_6 = 5 << 22,
 
     /**
-     *  display gamma 2.8.
-     *
+     * Display gamma 2.8.
+     * <pre>
      * Transfer characteristic curve:
-     *  E = L ^ (1/2.8)
-     *      L - luminance of image 0 <= L <= 1 for conventional colorimetry
-     *      E - corresponding electrical signal
+     * E = L ^ (1/2.8)
+     *     L - luminance of image 0 <= L <= 1 for conventional colorimetry
+     *     E - corresponding electrical signal</pre>
      */
     TRANSFER_GAMMA2_8 = 6 << 22,
 
     /**
-     * SMPTE ST 2084 (Dolby Perceptual Quantizer)
-     *
+     * SMPTE ST 2084 (Dolby Perceptual Quantizer).
+     * <pre>
      * Transfer characteristic curve:
-     *  E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
-     *  c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
-     *  c2 = 32 * 2413 / 4096 = 18.8515625
-     *  c3 = 32 * 2392 / 4096 = 18.6875
-     *  m = 128 * 2523 / 4096 = 78.84375
-     *  n = 0.25 * 2610 / 4096 = 0.1593017578125
-     *      L - luminance of image 0 <= L <= 1 for HDR colorimetry.
-     *          L = 1 corresponds to 10000 cd/m2
-     *      E - corresponding electrical signal
+     * E = ((c1 + c2 * L^n) / (1 + c3 * L^n)) ^ m
+     * c1 = c3 - c2 + 1 = 3424 / 4096 = 0.8359375
+     * c2 = 32 * 2413 / 4096 = 18.8515625
+     * c3 = 32 * 2392 / 4096 = 18.6875
+     * m = 128 * 2523 / 4096 = 78.84375
+     * n = 0.25 * 2610 / 4096 = 0.1593017578125
+     *     L - luminance of image 0 <= L <= 1 for HDR colorimetry.
+     *         L = 1 corresponds to 10000 cd/m2
+     *     E - corresponding electrical signal</pre>
      */
     TRANSFER_ST2084 = 7 << 22,
 
     /**
-     * ARIB STD-B67 Hybrid Log Gamma
-     *
+     * ARIB STD-B67 Hybrid Log Gamma.
+     * <pre>
      * Transfer characteristic curve:
      *  E = r * L^0.5                 for 0 <= L <= 1
      *    = a * ln(L - b) + c         for 1 < L
@@ -328,7 +342,7 @@
      *  r = 0.5
      *      L - luminance of image 0 <= L for HDR colorimetry. L = 1 corresponds
      *          to reference white level of 100 cd/m2
-     *      E - corresponding electrical signal
+     *      E - corresponding electrical signal</pre>
      */
     TRANSFER_HLG = 8 << 22,
 
@@ -384,21 +398,22 @@
     RANGE_EXTENDED = 3 << 27,
 
     /**
-     * scRGB linear encoding:
+     * scRGB linear encoding
      *
      * The red, green, and blue components are stored in extended sRGB space,
      * but are linear, not gamma-encoded.
-     * The RGB primaries and the white point are the same as BT.709.
      *
      * The values are floating point.
      * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits.
      * Values beyond the range [0.0 - 1.0] would correspond to other colors
      * spaces and/or HDR content.
+     *
+     * Uses extended range, linear transfer and BT.709 standard.
      */
     ADATASPACE_SCRGB_LINEAR = 406913024, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_EXTENDED
 
     /**
-     * sRGB gamma encoding:
+     * sRGB gamma encoding
      *
      * The red, green and blue components are stored in sRGB space, and
      * converted to linear space when read, using the SRGB transfer function
@@ -408,29 +423,29 @@
      * The alpha component, if present, is always stored in linear space and
      * is left unmodified when read or written.
      *
-     * Use full range and BT.709 standard.
+     * Uses full range, sRGB transfer BT.709 standard.
      */
     ADATASPACE_SRGB = 142671872, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_FULL
 
     /**
-     * scRGB:
+     * scRGB
      *
      * The red, green, and blue components are stored in extended sRGB space,
      * and gamma-encoded using the SRGB transfer function.
-     * The RGB primaries and the white point are the same as BT.709.
      *
      * The values are floating point.
      * A pixel value of 1.0, 1.0, 1.0 corresponds to sRGB white (D65) at 80 nits.
      * Values beyond the range [0.0 - 1.0] would correspond to other colors
      * spaces and/or HDR content.
+     *
+     * Uses extended range, sRGB transfer and BT.709 standard.
      */
     ADATASPACE_SCRGB = 411107328, // STANDARD_BT709 | TRANSFER_SRGB | RANGE_EXTENDED
 
     /**
      * Display P3
      *
-     * Use same primaries and white-point as DCI-P3
-     * but sRGB transfer function.
+     * Uses full range, sRGB transfer and D65 DCI-P3 standard.
      */
     ADATASPACE_DISPLAY_P3 = 143261696, // STANDARD_DCI_P3 | TRANSFER_SRGB | RANGE_FULL
 
@@ -439,7 +454,7 @@
      *
      * Ultra High-definition television
      *
-     * Use full range, SMPTE 2084 (PQ) transfer and BT2020 standard
+     * Uses full range, SMPTE 2084 (PQ) transfer and BT2020 standard.
      */
     ADATASPACE_BT2020_PQ = 163971072, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_FULL
 
@@ -448,14 +463,14 @@
      *
      * Ultra High-definition television
      *
-     * Use limited range, SMPTE 2084 (PQ) transfer and BT2020 standard
+     * Uses limited range, SMPTE 2084 (PQ) transfer and BT2020 standard.
      */
     ADATASPACE_BT2020_ITU_PQ = 298188800, // STANDARD_BT2020 | TRANSFER_ST2084 | RANGE_LIMITED
 
     /**
      * Adobe RGB
      *
-     * Use full range, gamma 2.2 transfer and Adobe RGB primaries
+     * Uses full range, gamma 2.2 transfer and Adobe RGB standard.
      *
      * Note: Application is responsible for gamma encoding the data as
      * a 2.2 gamma encoding is not supported in HW.
@@ -465,9 +480,9 @@
     /**
      * JPEG File Interchange Format (JFIF)
      *
-     * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255
+     * Same model as BT.601-625, but all values (Y, Cb, Cr) range from 0 to 255.
      *
-     * Use full range, SMPTE 170M transfer and BT.601_625 standard.
+     * Uses full range, SMPTE 170M transfer and BT.601_625 standard.
      */
     ADATASPACE_JFIF = 146931712, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_FULL
 
@@ -476,7 +491,7 @@
      *
      * Standard-definition television, 625 Lines (PAL)
      *
-     * Use limited range, SMPTE 170M transfer and BT.601_625 standard.
+     * Uses limited range, SMPTE 170M transfer and BT.601_625 standard.
      */
     ADATASPACE_BT601_625 = 281149440, // STANDARD_BT601_625 | TRANSFER_SMPTE_170M | RANGE_LIMITED
 
@@ -485,7 +500,7 @@
      *
      * Standard-definition television, 525 Lines (NTSC)
      *
-     * Use limited range, SMPTE 170M transfer and BT.601_525 standard.
+     * Uses limited range, SMPTE 170M transfer and BT.601_525 standard.
      */
     ADATASPACE_BT601_525 = 281280512, // STANDARD_BT601_525 | TRANSFER_SMPTE_170M | RANGE_LIMITED
 
@@ -494,7 +509,7 @@
      *
      * Ultra High-definition television
      *
-     * Use full range, SMPTE 170M transfer and BT2020 standard
+     * Uses full range, SMPTE 170M transfer and BT2020 standard.
      */
     ADATASPACE_BT2020 = 147193856, // STANDARD_BT2020 | TRANSFER_SMPTE_170M | RANGE_FULL
 
@@ -503,16 +518,16 @@
      *
      * High-definition television
      *
-     * Use limited range, SMPTE 170M transfer and BT.709 standard.
+     * Uses limited range, SMPTE 170M transfer and BT.709 standard.
      */
     ADATASPACE_BT709 = 281083904, // STANDARD_BT709 | TRANSFER_SMPTE_170M | RANGE_LIMITED
 
     /**
-     * SMPTE EG 432-1 and SMPTE RP 431-2.
+     * SMPTE EG 432-1 and SMPTE RP 431-2
      *
      * Digital Cinema DCI-P3
      *
-     * Use full range, gamma 2.6 transfer and D65 DCI-P3 standard
+     * Uses full range, gamma 2.6 transfer and D65 DCI-P3 standard.
      *
      * Note: Application is responsible for gamma encoding the data as
      * a 2.6 gamma encoding is not supported in HW.
@@ -520,7 +535,7 @@
     ADATASPACE_DCI_P3 = 155844608, // STANDARD_DCI_P3 | TRANSFER_GAMMA2_6 | RANGE_FULL
 
     /**
-     * sRGB linear encoding:
+     * sRGB linear encoding
      *
      * The red, green, and blue components are stored in sRGB space, but
      * are linear, not gamma-encoded.
@@ -528,32 +543,34 @@
      *
      * The values are encoded using the full range ([0,255] for 8-bit) for all
      * components.
+     *
+     * Uses full range, linear transfer and BT.709 standard.
      */
     ADATASPACE_SRGB_LINEAR = 138477568, // STANDARD_BT709 | TRANSFER_LINEAR | RANGE_FULL
 
     /**
-     * Hybrid Log Gamma encoding:
+     * Hybrid Log Gamma encoding
      *
-     * Use full range, hybrid log gamma transfer and BT2020 standard.
+     * Uses full range, hybrid log gamma transfer and BT2020 standard.
      */
     ADATASPACE_BT2020_HLG = 168165376, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_FULL
 
     /**
-     * ITU Hybrid Log Gamma encoding:
+     * ITU Hybrid Log Gamma encoding
      *
-     * Use limited range, hybrid log gamma transfer and BT2020 standard.
+     * Uses limited range, hybrid log gamma transfer and BT2020 standard.
      */
     ADATASPACE_BT2020_ITU_HLG = 302383104, // STANDARD_BT2020 | TRANSFER_HLG | RANGE_LIMITED
 
     /**
-     * Depth:
+     * Depth
      *
      * This value is valid with formats HAL_PIXEL_FORMAT_Y16 and HAL_PIXEL_FORMAT_BLOB.
      */
     ADATASPACE_DEPTH = 4096,
 
     /**
-     * ISO 16684-1:2011(E) Dynamic Depth:
+     * ISO 16684-1:2011(E) Dynamic Depth
      *
      * Embedded depth metadata following the dynamic depth specification.
      */
diff --git a/libs/nativewindow/rust/Android.bp b/libs/nativewindow/rust/Android.bp
new file mode 100644
index 0000000..dc1575c
--- /dev/null
+++ b/libs/nativewindow/rust/Android.bp
@@ -0,0 +1,87 @@
+// Copyright (C) 2023 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 {
+    default_applicable_licenses: [
+        "frameworks_native_libs_nativewindow_license",
+    ],
+}
+
+rust_bindgen {
+    name: "libnativewindow_bindgen",
+    crate_name: "nativewindow_bindgen",
+    wrapper_src: "sys/nativewindow_bindings.h",
+    source_stem: "bindings",
+    bindgen_flags: [
+        "--constified-enum-module=AHardwareBuffer_Format",
+        "--bitfield-enum=AHardwareBuffer_UsageFlags",
+
+        "--allowlist-file=.*/nativewindow/include/.*\\.h",
+
+        "--with-derive-eq",
+        "--with-derive-partialeq",
+    ],
+    shared_libs: [
+        "libnativewindow",
+    ],
+
+    // Currently necessary for host builds
+    // TODO(b/31559095): bionic on host should define this
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    min_sdk_version: "VanillaIceCream",
+}
+
+rust_test {
+    name: "libnativewindow_bindgen_test",
+    srcs: [":libnativewindow_bindgen"],
+    crate_name: "nativewindow_bindgen_test",
+    test_suites: ["general-tests"],
+    auto_gen_config: true,
+    clippy_lints: "none",
+    lints: "none",
+}
+
+rust_defaults {
+    name: "libnativewindow_defaults",
+    srcs: ["src/lib.rs"],
+    rustlibs: [
+        "libnativewindow_bindgen",
+    ],
+}
+
+rust_library {
+    name: "libnativewindow_rs",
+    crate_name: "nativewindow",
+    defaults: ["libnativewindow_defaults"],
+
+    // Currently necessary for host builds
+    // TODO(b/31559095): bionic on host should define this
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    min_sdk_version: "VanillaIceCream",
+}
+
+rust_test {
+    name: "libnativewindow_rs-internal_test",
+    crate_name: "nativewindow",
+    defaults: ["libnativewindow_defaults"],
+    test_suites: ["general-tests"],
+}
diff --git a/libs/nativewindow/rust/src/lib.rs b/libs/nativewindow/rust/src/lib.rs
new file mode 100644
index 0000000..6eb3bbc
--- /dev/null
+++ b/libs/nativewindow/rust/src/lib.rs
@@ -0,0 +1,329 @@
+// Copyright (C) 2023 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.
+
+//! Pleasant Rust bindings for libnativewindow, including AHardwareBuffer
+
+extern crate nativewindow_bindgen as ffi;
+
+pub use ffi::{AHardwareBuffer, AHardwareBuffer_Format, AHardwareBuffer_UsageFlags};
+
+use std::fmt::{self, Debug, Formatter};
+use std::mem::ManuallyDrop;
+use std::ptr::{self, NonNull};
+
+/// Wrapper around an opaque C AHardwareBuffer.
+#[derive(PartialEq, Eq)]
+pub struct HardwareBuffer(NonNull<AHardwareBuffer>);
+
+impl HardwareBuffer {
+    /// Test whether the given format and usage flag combination is allocatable.  If this function
+    /// returns true, it means that a buffer with the given description can be allocated on this
+    /// implementation, unless resource exhaustion occurs. If this function returns false, it means
+    /// that the allocation of the given description will never succeed.
+    ///
+    /// Available since API 29
+    pub fn is_supported(
+        width: u32,
+        height: u32,
+        layers: u32,
+        format: AHardwareBuffer_Format::Type,
+        usage: AHardwareBuffer_UsageFlags,
+        stride: u32,
+    ) -> bool {
+        let buffer_desc = ffi::AHardwareBuffer_Desc {
+            width,
+            height,
+            layers,
+            format,
+            usage: usage.0,
+            stride,
+            rfu0: 0,
+            rfu1: 0,
+        };
+        // SAFETY: *buffer_desc will never be null.
+        let status = unsafe { ffi::AHardwareBuffer_isSupported(&buffer_desc) };
+
+        status == 1
+    }
+
+    /// Allocates a buffer that matches the passed AHardwareBuffer_Desc. If allocation succeeds, the
+    /// buffer can be used according to the usage flags specified in its description. If a buffer is
+    /// used in ways not compatible with its usage flags, the results are undefined and may include
+    /// program termination.
+    ///
+    /// Available since API level 26.
+    #[inline]
+    pub fn new(
+        width: u32,
+        height: u32,
+        layers: u32,
+        format: AHardwareBuffer_Format::Type,
+        usage: AHardwareBuffer_UsageFlags,
+    ) -> Option<Self> {
+        let buffer_desc = ffi::AHardwareBuffer_Desc {
+            width,
+            height,
+            layers,
+            format,
+            usage: usage.0,
+            stride: 0,
+            rfu0: 0,
+            rfu1: 0,
+        };
+        let mut ptr = ptr::null_mut();
+        // SAFETY: The returned pointer is valid until we drop/deallocate it. The function may fail
+        // and return a status, but we check it later.
+        let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut ptr) };
+
+        if status == 0 {
+            Some(Self(NonNull::new(ptr).expect("Allocated AHardwareBuffer was null")))
+        } else {
+            None
+        }
+    }
+
+    /// Adopts the raw pointer and wraps it in a Rust AHardwareBuffer.
+    ///
+    /// # Errors
+    ///
+    /// Will panic if buffer_ptr is null.
+    ///
+    /// # Safety
+    ///
+    /// This function adopts the pointer but does NOT increment the refcount on the buffer. If the
+    /// caller uses the pointer after the created object is dropped it will cause a memory leak.
+    pub unsafe fn from_raw(buffer_ptr: NonNull<AHardwareBuffer>) -> Self {
+        Self(buffer_ptr)
+    }
+
+    /// Get the internal |AHardwareBuffer| pointer without decrementing the refcount. This can
+    /// be used to provide a pointer to the AHB for a C/C++ API over the FFI.
+    pub fn into_raw(self) -> NonNull<AHardwareBuffer> {
+        let buffer = ManuallyDrop::new(self);
+        buffer.0
+    }
+
+    /// Get the system wide unique id for an AHardwareBuffer. This function may panic in extreme
+    /// and undocumented circumstances.
+    ///
+    /// Available since API level 31.
+    pub fn id(&self) -> u64 {
+        let mut out_id = 0;
+        // SAFETY: Neither pointers can be null.
+        let status = unsafe { ffi::AHardwareBuffer_getId(self.0.as_ref(), &mut out_id) };
+        assert_eq!(status, 0, "id() failed for AHardwareBuffer with error code: {status}");
+
+        out_id
+    }
+
+    /// Get the width of this buffer
+    pub fn width(&self) -> u32 {
+        self.description().width
+    }
+
+    /// Get the height of this buffer
+    pub fn height(&self) -> u32 {
+        self.description().height
+    }
+
+    /// Get the number of layers of this buffer
+    pub fn layers(&self) -> u32 {
+        self.description().layers
+    }
+
+    /// Get the format of this buffer
+    pub fn format(&self) -> AHardwareBuffer_Format::Type {
+        self.description().format
+    }
+
+    /// Get the usage bitvector of this buffer
+    pub fn usage(&self) -> AHardwareBuffer_UsageFlags {
+        AHardwareBuffer_UsageFlags(self.description().usage)
+    }
+
+    /// Get the stride of this buffer
+    pub fn stride(&self) -> u32 {
+        self.description().stride
+    }
+
+    fn description(&self) -> ffi::AHardwareBuffer_Desc {
+        let mut buffer_desc = ffi::AHardwareBuffer_Desc {
+            width: 0,
+            height: 0,
+            layers: 0,
+            format: 0,
+            usage: 0,
+            stride: 0,
+            rfu0: 0,
+            rfu1: 0,
+        };
+        // SAFETY: neither the buffer nor AHardwareBuffer_Desc pointers will be null.
+        unsafe { ffi::AHardwareBuffer_describe(self.0.as_ref(), &mut buffer_desc) };
+        buffer_desc
+    }
+}
+
+impl Drop for HardwareBuffer {
+    fn drop(&mut self) {
+        // SAFETY: self.0 will never be null. AHardwareBuffers allocated from within Rust will have
+        // a refcount of one, and there is a safety warning on taking an AHardwareBuffer from a raw
+        // pointer requiring callers to ensure the refcount is managed appropriately.
+        unsafe { ffi::AHardwareBuffer_release(self.0.as_ptr()) }
+    }
+}
+
+impl Debug for HardwareBuffer {
+    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+        f.debug_struct("HardwareBuffer").field("id", &self.id()).finish()
+    }
+}
+
+impl Clone for HardwareBuffer {
+    fn clone(&self) -> Self {
+        // SAFETY: ptr is guaranteed to be non-null and the acquire can not fail.
+        unsafe { ffi::AHardwareBuffer_acquire(self.0.as_ptr()) };
+        Self(self.0)
+    }
+}
+
+// SAFETY: The underlying *AHardwareBuffers can be moved between threads.
+unsafe impl Send for HardwareBuffer {}
+
+// SAFETY: The underlying *AHardwareBuffers can be used from multiple threads.
+//
+// AHardwareBuffers are backed by C++ GraphicBuffers, which are mostly immutable. The only cases
+// where they are not immutable are:
+//
+//   - reallocation (which is never actually done across the codebase and requires special
+//     privileges/platform code access to do)
+//   - "locking" for reading/writing (which is explicitly allowed to be done across multiple threads
+//     according to the docs on the underlying gralloc calls)
+unsafe impl Sync for HardwareBuffer {}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    #[test]
+    fn create_valid_buffer_returns_ok() {
+        let buffer = HardwareBuffer::new(
+            512,
+            512,
+            1,
+            AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+            AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+        );
+        assert!(buffer.is_some());
+    }
+
+    #[test]
+    fn create_invalid_buffer_returns_err() {
+        let buffer = HardwareBuffer::new(512, 512, 1, 0, AHardwareBuffer_UsageFlags(0));
+        assert!(buffer.is_none());
+    }
+
+    #[test]
+    fn from_raw_allows_getters() {
+        let buffer_desc = ffi::AHardwareBuffer_Desc {
+            width: 1024,
+            height: 512,
+            layers: 1,
+            format: AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+            usage: AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN.0,
+            stride: 0,
+            rfu0: 0,
+            rfu1: 0,
+        };
+        let mut raw_buffer_ptr = ptr::null_mut();
+
+        // SAFETY: The pointers are valid because they come from references, and
+        // `AHardwareBuffer_allocate` doesn't retain them after it returns.
+        let status = unsafe { ffi::AHardwareBuffer_allocate(&buffer_desc, &mut raw_buffer_ptr) };
+        assert_eq!(status, 0);
+
+        // SAFETY: The pointer must be valid because it was just allocated successfully, and we
+        // don't use it after calling this.
+        let buffer = unsafe { HardwareBuffer::from_raw(NonNull::new(raw_buffer_ptr).unwrap()) };
+        assert_eq!(buffer.width(), 1024);
+    }
+
+    #[test]
+    fn basic_getters() {
+        let buffer = HardwareBuffer::new(
+            1024,
+            512,
+            1,
+            AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+            AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+        )
+        .expect("Buffer with some basic parameters was not created successfully");
+
+        assert_eq!(buffer.width(), 1024);
+        assert_eq!(buffer.height(), 512);
+        assert_eq!(buffer.layers(), 1);
+        assert_eq!(buffer.format(), AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM);
+        assert_eq!(
+            buffer.usage(),
+            AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN
+        );
+    }
+
+    #[test]
+    fn id_getter() {
+        let buffer = HardwareBuffer::new(
+            1024,
+            512,
+            1,
+            AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+            AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+        )
+        .expect("Buffer with some basic parameters was not created successfully");
+
+        assert_ne!(0, buffer.id());
+    }
+
+    #[test]
+    fn clone() {
+        let buffer = HardwareBuffer::new(
+            1024,
+            512,
+            1,
+            AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+            AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+        )
+        .expect("Buffer with some basic parameters was not created successfully");
+        let buffer2 = buffer.clone();
+
+        assert_eq!(buffer, buffer2);
+    }
+
+    #[test]
+    fn into_raw() {
+        let buffer = HardwareBuffer::new(
+            1024,
+            512,
+            1,
+            AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+            AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+        )
+        .expect("Buffer with some basic parameters was not created successfully");
+        let buffer2 = buffer.clone();
+
+        let raw_buffer = buffer.into_raw();
+        // SAFETY: This is the same pointer we had before.
+        let remade_buffer = unsafe { HardwareBuffer::from_raw(raw_buffer) };
+
+        assert_eq!(remade_buffer, buffer2);
+    }
+}
diff --git a/libs/nativewindow/rust/sys/nativewindow_bindings.h b/libs/nativewindow/rust/sys/nativewindow_bindings.h
new file mode 100644
index 0000000..e652aee
--- /dev/null
+++ b/libs/nativewindow/rust/sys/nativewindow_bindings.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/data_space.h>
+#include <android/hardware_buffer.h>
+#include <android/hdr_metadata.h>
+#include <android/native_window.h>
diff --git a/libs/nativewindow/tests/benchmark/Android.bp b/libs/nativewindow/tests/benchmark/Android.bp
new file mode 100644
index 0000000..6f844cf
--- /dev/null
+++ b/libs/nativewindow/tests/benchmark/Android.bp
@@ -0,0 +1,50 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+cc_defaults {
+    name: "nativewindow_benchmark_defaults_cc",
+    shared_libs: ["libnativewindow"],
+    static_libs: [
+        "libbase",
+        "libgoogle-benchmark-main",
+    ],
+    test_suites: [
+        "device-tests",
+        "NativeWindowBenchmarks",
+    ],
+}
+
+cc_benchmark {
+    name: "nativewindow_buffer_benchmarks_cc",
+    srcs: ["buffer_benchmarks.cc"],
+    defaults: ["nativewindow_benchmark_defaults_cc"],
+}
+
+rust_defaults {
+    name: "nativewindow_benchmark_defaults_rs",
+    rustlibs: [
+        "libnativewindow_rs",
+        "libcriterion",
+    ],
+    test_suites: [
+        "device-tests",
+        "NativeWindowBenchmarks",
+    ],
+}
+
+rust_benchmark {
+    name: "nativewindow_buffer_benchmarks_rs",
+    srcs: ["buffer_benchmarks.rs"],
+    defaults: ["nativewindow_benchmark_defaults_rs"],
+}
diff --git a/libs/nativewindow/tests/benchmark/README.md b/libs/nativewindow/tests/benchmark/README.md
new file mode 100644
index 0000000..7eae538
--- /dev/null
+++ b/libs/nativewindow/tests/benchmark/README.md
@@ -0,0 +1,22 @@
+# libnativewindow Benchmarks
+
+This directory contains benchmarks for the C++ and Rust variants of
+libnativewindow.
+
+## Running
+
+It is currently a little tricky to get statistics from Rust benchmarks directly
+from tradefed. But we can hack it by using atest to build/push, then running
+the benchmarks by hand to get stats.
+
+```
+  $ atest nativewindow_buffer_benchmarks_rs nativewindow_buffer_benchmarks_cc -d
+  $ adb shell /data/local/tmp/nativewindow_buffer_benchmarks_cc/x86_64/nativewindow_buffer_benchmarks_cc
+  $ adb shell /data/local/tmp/nativewindow_buffer_benchmarks_rs/x86_64/nativewindow_buffer_benchmarks_rs --bench
+```
+
+## Results
+
+On a remote emulator, the results we see from the benchmarks from Rust and C++
+seem to be roughly equivalent! Allocating/deallocating a 720p buffer takes
+~2.3ms on each.
diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc
new file mode 100644
index 0000000..9b31993
--- /dev/null
+++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.cc
@@ -0,0 +1,74 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <android-base/macros.h>
+#include <android/hardware_buffer.h>
+#include <benchmark/benchmark.h>
+
+constexpr AHardwareBuffer_Desc k720pDesc = {.width = 1280,
+                                            .height = 720,
+                                            .layers = 1,
+                                            .format = AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+                                            .usage = AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+                                            .stride = 0};
+
+static void BM_BufferAllocationDeallocation(benchmark::State& state) {
+    AHardwareBuffer* buffer = nullptr;
+    for (auto _ : state) {
+        int status = AHardwareBuffer_allocate(&k720pDesc, &buffer);
+        if (UNLIKELY(status != 0)) {
+            state.SkipWithError("Unable to allocate buffer.");
+        }
+        AHardwareBuffer_release(buffer);
+        buffer = nullptr;
+    }
+}
+BENCHMARK(BM_BufferAllocationDeallocation);
+
+static void BM_AHardwareBuffer_Id(benchmark::State& state) {
+    AHardwareBuffer* buffer = nullptr;
+    int status = AHardwareBuffer_allocate(&k720pDesc, &buffer);
+    if (UNLIKELY(status != 0)) {
+        state.SkipWithError("Unable to allocate buffer.");
+    }
+
+    for (auto _ : state) {
+        uint64_t id = 0;
+        int status = AHardwareBuffer_getId(buffer, &id);
+        if (UNLIKELY(status != 0)) {
+            state.SkipWithError("Unable to get ID.");
+        }
+    }
+
+    AHardwareBuffer_release(buffer);
+}
+BENCHMARK(BM_AHardwareBuffer_Id);
+
+static void BM_AHardwareBuffer_Desc(benchmark::State& state) {
+    AHardwareBuffer* buffer = nullptr;
+    int status = AHardwareBuffer_allocate(&k720pDesc, &buffer);
+    if (UNLIKELY(status != 0)) {
+        state.SkipWithError("Unable to allocate buffer.");
+    }
+
+    for (auto _ : state) {
+        AHardwareBuffer_Desc desc = {};
+        AHardwareBuffer_describe(buffer, &desc);
+    }
+
+    AHardwareBuffer_release(buffer);
+}
+BENCHMARK(BM_AHardwareBuffer_Desc);
+
+BENCHMARK_MAIN();
diff --git a/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
new file mode 100644
index 0000000..876f6c8
--- /dev/null
+++ b/libs/nativewindow/tests/benchmark/buffer_benchmarks.rs
@@ -0,0 +1,60 @@
+// Copyright (C) 2023 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.
+
+//! Benchmark for libnativewindow AHardwareBuffer bindings
+
+#![allow(dead_code)]
+#![allow(missing_docs)]
+
+use criterion::*;
+use nativewindow::*;
+
+#[inline]
+fn create_720p_buffer() -> HardwareBuffer {
+    HardwareBuffer::new(
+        1280,
+        720,
+        1,
+        AHardwareBuffer_Format::AHARDWAREBUFFER_FORMAT_R8G8B8A8_UNORM,
+        AHardwareBuffer_UsageFlags::AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN,
+    )
+    .unwrap()
+}
+
+fn criterion_benchmark(c: &mut Criterion) {
+    c.bench_function("allocate_deallocate", |b| {
+        b.iter(|| {
+            let buffer = create_720p_buffer();
+            drop(buffer);
+        })
+    });
+
+    let buffer = create_720p_buffer();
+    c.bench_with_input(BenchmarkId::new("id", "buffer"), &buffer, |b, buffer| {
+        b.iter(|| {
+            buffer.id();
+        })
+    });
+
+    // This benchmark exercises getters that need to fetch data via an
+    // underlying call to AHardwareBuffer_describe.
+    c.bench_with_input(BenchmarkId::new("desc", "buffer"), &buffer, |b, buffer| {
+        b.iter(|| {
+            buffer.width();
+        })
+    });
+}
+
+criterion_group!(benches, criterion_benchmark);
+criterion_main!(benches);
diff --git a/libs/vibrator/OWNERS b/libs/vibrator/OWNERS
index d073e2b..c4de58a 100644
--- a/libs/vibrator/OWNERS
+++ b/libs/vibrator/OWNERS
@@ -1 +1,2 @@
+# Bug component: 345036
 include platform/frameworks/base:/services/core/java/com/android/server/vibrator/OWNERS
diff --git a/services/inputflinger/dispatcher/InputDispatcher.cpp b/services/inputflinger/dispatcher/InputDispatcher.cpp
index 5c524d3..901c806 100644
--- a/services/inputflinger/dispatcher/InputDispatcher.cpp
+++ b/services/inputflinger/dispatcher/InputDispatcher.cpp
@@ -3900,6 +3900,16 @@
 
 void InputDispatcher::synthesizeCancelationEventsForConnectionLocked(
         const std::shared_ptr<Connection>& connection, const CancelationOptions& options) {
+    if ((options.mode == CancelationOptions::Mode::CANCEL_POINTER_EVENTS ||
+         options.mode == CancelationOptions::Mode::CANCEL_ALL_EVENTS) &&
+        mDragState && mDragState->dragWindow->getToken() == connection->inputChannel->getToken()) {
+        LOG(INFO) << __func__
+                  << ": Canceling drag and drop because the pointers for the drag window are being "
+                     "canceled.";
+        sendDropWindowCommandLocked(nullptr, /*x=*/0, /*y=*/0);
+        mDragState.reset();
+    }
+
     if (connection->status == Connection::Status::BROKEN) {
         return;
     }
@@ -3924,8 +3934,13 @@
             << connection->getInputChannelName().c_str() << reason << LOG_ID_EVENTS;
 
     InputTarget target;
-    sp<WindowInfoHandle> windowHandle =
-            getWindowHandleLocked(connection->inputChannel->getConnectionToken());
+    sp<WindowInfoHandle> windowHandle;
+    if (options.displayId) {
+        windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken(),
+                                             options.displayId.value());
+    } else {
+        windowHandle = getWindowHandleLocked(connection->inputChannel->getConnectionToken());
+    }
     if (windowHandle != nullptr) {
         const WindowInfo* windowInfo = windowHandle->getInfo();
         target.setDefaultPointerTransform(windowInfo->transform);
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index 6ff420d..f3aba79 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -4153,6 +4153,61 @@
 }
 
 /**
+ * When there are multiple screens, such as screen projection to TV or screen recording, if the
+ * cancel event occurs, the coordinates of the cancel event should be sent to the target screen, and
+ * its coordinates should be converted by the transform of the windows of target screen.
+ */
+TEST_F(InputDispatcherTest, WhenMultiDisplayWindowSameToken_DispatchCancelToTargetDisplay) {
+    // This case will create a window and a spy window on the default display and mirror
+    //  window on the second display. cancel event is sent through spy  window pilferPointers
+    std::shared_ptr<FakeApplicationHandle> application = std::make_shared<FakeApplicationHandle>();
+
+    sp<FakeWindowHandle> spyWindowDefaultDisplay =
+            sp<FakeWindowHandle>::make(application, mDispatcher, "Spy", ADISPLAY_ID_DEFAULT);
+    spyWindowDefaultDisplay->setTrustedOverlay(true);
+    spyWindowDefaultDisplay->setSpy(true);
+
+    sp<FakeWindowHandle> windowDefaultDisplay =
+            sp<FakeWindowHandle>::make(application, mDispatcher, "DefaultDisplay",
+                                       ADISPLAY_ID_DEFAULT);
+    windowDefaultDisplay->setWindowTransform(1, 0, 0, 1);
+
+    sp<FakeWindowHandle> windowSecondDisplay =
+            windowDefaultDisplay->clone(application, mDispatcher, SECOND_DISPLAY_ID);
+    windowSecondDisplay->setWindowTransform(2, 0, 0, 2);
+
+    // Add the windows to the dispatcher
+    mDispatcher->onWindowInfosChanged(
+            {{*spyWindowDefaultDisplay->getInfo(), *windowDefaultDisplay->getInfo(),
+              *windowSecondDisplay->getInfo()},
+             {},
+             0,
+             0});
+
+    // Send down to ADISPLAY_ID_DEFAULT
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {100, 100}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+    spyWindowDefaultDisplay->consumeMotionDown();
+    windowDefaultDisplay->consumeMotionDown();
+
+    EXPECT_EQ(OK, mDispatcher->pilferPointers(spyWindowDefaultDisplay->getToken()));
+
+    // windowDefaultDisplay gets cancel
+    MotionEvent* event = windowDefaultDisplay->consumeMotion();
+    EXPECT_EQ(AMOTION_EVENT_ACTION_CANCEL, event->getAction());
+
+    // The cancel event is sent to windowDefaultDisplay of the ADISPLAY_ID_DEFAULT display, so the
+    // coordinates of the cancel are converted by windowDefaultDisplay's transform, the x and y
+    // coordinates are both 100, otherwise if the cancel event is sent to windowSecondDisplay of
+    // SECOND_DISPLAY_ID, the x and y coordinates are 200
+    EXPECT_EQ(100, event->getX(0));
+    EXPECT_EQ(100, event->getY(0));
+}
+
+/**
  * Ensure the correct coordinate spaces are used by InputDispatcher.
  *
  * InputDispatcher works in the display space, so its coordinate system is relative to the display
@@ -8697,6 +8752,75 @@
     mSecondWindow->assertNoEvents();
 }
 
+/**
+ * Start drag and drop with a pointer whose id is not 0, cancel the current touch, and ensure drag
+ * and drop is also canceled. Then inject a simple gesture, and ensure dispatcher does not crash.
+ */
+TEST_F(InputDispatcherDragTests, DragAndDropFinishedWhenCancelCurrentTouch) {
+    // Down on second window
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               {150, 50}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+
+    ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionDown());
+    ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionDown());
+
+    // Down on first window
+    const MotionEvent secondFingerDownEvent =
+            MotionEventBuilder(POINTER_1_DOWN, AINPUT_SOURCE_TOUCHSCREEN)
+                    .displayId(ADISPLAY_ID_DEFAULT)
+                    .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(150).y(50))
+                    .pointer(PointerBuilder(/*id=*/1, ToolType::FINGER).x(50).y(50))
+                    .build();
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, secondFingerDownEvent, INJECT_EVENT_TIMEOUT,
+                                InputEventInjectionSync::WAIT_FOR_RESULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
+    ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionMove());
+    ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionPointerDown(1));
+
+    // Start drag on first window
+    ASSERT_TRUE(startDrag(/*sendDown=*/false, AINPUT_SOURCE_TOUCHSCREEN));
+
+    // Trigger cancel
+    mDispatcher->cancelCurrentTouch();
+    ASSERT_NO_FATAL_FAILURE(mSecondWindow->consumeMotionCancel());
+    ASSERT_NO_FATAL_FAILURE(mDragWindow->consumeMotionCancel());
+    ASSERT_NO_FATAL_FAILURE(mSpyWindow->consumeMotionCancel());
+
+    ASSERT_TRUE(mDispatcher->waitForIdle());
+    // The D&D finished with nullptr
+    mFakePolicy->assertDropTargetEquals(nullptr);
+
+    // Remove drag window
+    mDispatcher->onWindowInfosChanged({{*mWindow->getInfo(), *mSecondWindow->getInfo()}, {}, 0, 0});
+
+    // Inject a simple gesture, ensure dispatcher not crashed
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionDown(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT,
+                               PointF{50, 50}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionDown());
+
+    const MotionEvent moveEvent =
+            MotionEventBuilder(AMOTION_EVENT_ACTION_MOVE, AINPUT_SOURCE_TOUCHSCREEN)
+                    .displayId(ADISPLAY_ID_DEFAULT)
+                    .pointer(PointerBuilder(/*id=*/0, ToolType::FINGER).x(50).y(50))
+                    .build();
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionEvent(mDispatcher, moveEvent, INJECT_EVENT_TIMEOUT,
+                                InputEventInjectionSync::WAIT_FOR_RESULT))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionMove());
+
+    ASSERT_EQ(InputEventInjectionResult::SUCCEEDED,
+              injectMotionUp(mDispatcher, AINPUT_SOURCE_TOUCHSCREEN, ADISPLAY_ID_DEFAULT, {50, 50}))
+            << "Inject motion event should return InputEventInjectionResult::SUCCEEDED";
+    ASSERT_NO_FATAL_FAILURE(mWindow->consumeMotionUp());
+}
+
 class InputDispatcherDropInputFeatureTest : public InputDispatcherTest {};
 
 TEST_F(InputDispatcherDropInputFeatureTest, WindowDropsInput) {